diff --git a/VERSION.txt b/VERSION.txt index 0f61437236d..479494e500d 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -Mercury-13.8.0 +Mercury-13.9.0 diff --git a/alpha/apps/kaltura/lib/batch/myBatchPartnerUsage.class.php b/alpha/apps/kaltura/lib/batch/myBatchPartnerUsage.class.php index 77b58806a29..f6aa5efcb8c 100644 --- a/alpha/apps/kaltura/lib/batch/myBatchPartnerUsage.class.php +++ b/alpha/apps/kaltura/lib/batch/myBatchPartnerUsage.class.php @@ -42,6 +42,8 @@ public function __construct($partnerId = null, $partnerPackage = PartnerPackages if($partnerPackage == PartnerPackages::PARTNER_PACKAGE_FREE) { myPartnerUtils::doPartnerUsage($partner, true); + if(myPartnerUtils::isPartnerCreatedAsMonitoredFreeTrial($partner)) + myPartnerUtils::handleDayInFreeTrial($partner); } else if($partnerPackage == PartnerPackages::PARTNER_PACKAGE_DEVELOPER) { @@ -50,7 +52,8 @@ public function __construct($partnerId = null, $partnerPackage = PartnerPackages } } $partner = end($partners); - $highest_partner_id = $partner->getId(); + if($partner) + $highest_partner_id = $partner->getId(); unset($partners); PartnerPeer::clearInstancePool(); } diff --git a/alpha/apps/kaltura/lib/batch2/bcdl/kBusinessPreConvertDL.php b/alpha/apps/kaltura/lib/batch2/bcdl/kBusinessPreConvertDL.php index c560568b1b3..7cde1eca995 100644 --- a/alpha/apps/kaltura/lib/batch2/bcdl/kBusinessPreConvertDL.php +++ b/alpha/apps/kaltura/lib/batch2/bcdl/kBusinessPreConvertDL.php @@ -314,14 +314,15 @@ private static function generateThumbnail(asset $srcAsset, thumbParamsOutput $de if($srcAsset->getType() == assetType::FLAVOR) { /* @var $srcAsset flavorAsset */ - $dar = null; + $params = array(); $mediaInfo = mediaInfoPeer::retrieveByFlavorAssetId($srcAsset->getId()); - if($mediaInfo) - $dar = $mediaInfo->getVideoDar(); - + if($mediaInfo){ + $params['dar'] = $mediaInfo->getVideoDar(); + $params['scanType'] = $mediaInfo->getScanType(); + } // generates the thumbnail $thumbMaker = new KFFMpegThumbnailMaker($srcPath, $destPath, kConf::get('bin_path_ffmpeg')); - $created = $thumbMaker->createThumnail($destThumbParamsOutput->getVideoOffset(), $srcAsset->getWidth(), $srcAsset->getHeight(), null, null, $dar); + $created = $thumbMaker->createThumnail($destThumbParamsOutput->getVideoOffset(), $srcAsset->getWidth(), $srcAsset->getHeight(), $params); if(!$created || !file_exists($destPath)) { $errDescription = "Thumbnail not captured"; @@ -1110,10 +1111,9 @@ public static function bypassConversion(flavorAsset $originalFlavorAsset, entry $offset = $entry->getThumbOffset(); // entry getThumbOffset now takes the partner DefThumbOffset into consideration $srcSyncKey = $originalFlavorAsset->getSyncKey(flavorAsset::FILE_SYNC_FLAVOR_ASSET_SUB_TYPE_ASSET); - $srcFileSyncLocalPath = kFileSyncUtils::getLocalFilePathForKey($srcSyncKey); - + $postConvertAssetType = BatchJob::POSTCONVERT_ASSET_TYPE_BYPASS; - return kJobsManager::addPostConvertJob($convertProfileJob, $postConvertAssetType, $srcFileSyncLocalPath, $originalFlavorAsset->getId(), null, true, $offset); + return kJobsManager::addPostConvertJob($convertProfileJob, $postConvertAssetType, $srcSyncKey, $originalFlavorAsset->getId(), null, true, $offset); } /** diff --git a/alpha/apps/kaltura/lib/batch2/kFlowHelper.php b/alpha/apps/kaltura/lib/batch2/kFlowHelper.php index 597d99d1743..844a619c51f 100644 --- a/alpha/apps/kaltura/lib/batch2/kFlowHelper.php +++ b/alpha/apps/kaltura/lib/batch2/kFlowHelper.php @@ -395,7 +395,7 @@ private static function createReplacigEntry($recordedEntry, $liveSegmentCount) return $replacingEntry; } - public static function getReplacingEntry($recordedEntry, $asset, $liveSegmentCount) + public static function getReplacingEntry($recordedEntry, $asset = null, $liveSegmentCount, $flavorParamsId = null) { //Reload entry before tryign to get the replacing entry id from it to avoid creating 2 different replacing entries for different flavors $recordedEntry->reload(); @@ -415,7 +415,8 @@ public static function getReplacingEntry($recordedEntry, $asset, $liveSegmentCou } else { - $replacingAsset = assetPeer::retrieveByEntryIdAndParams($replacingEntryId, $asset->getFlavorParamsId()); + $flavorParamsId = $asset ? $asset->getFlavorParamsId() : $flavorParamsId; + $replacingAsset = assetPeer::retrieveByEntryIdAndParams($replacingEntryId, $flavorParamsId); if($replacingAsset) { KalturaLog::debug("Entry in replacement, deleting - [".$replacingEntryId."]"); @@ -772,7 +773,7 @@ public static function handleConvertFinished(BatchJob $dbBatchJob, kConvertJobDa $nextJob = self::createNextJob($flavorParamsOutput, $dbBatchJob, $data, $syncKey); //todo validate sync key if(!$nextJob) { - self::handleOperatorsProcessingFinished($flavorAsset, $flavorParamsOutput, $entry, $dbBatchJob, $data, $rootBatchJob); + self::handleOperatorsProcessingFinished($flavorAsset, $flavorParamsOutput, $entry, $dbBatchJob, $data, $rootBatchJob, $syncKey); } // this logic decide when a thumbnail should be created if($rootBatchJob && $rootBatchJob->getJobType() == BatchJobType::BULKDOWNLOAD) @@ -840,7 +841,7 @@ private static function createNextJob(flavorParamsOutput $flavorParamsOutput, Ba return $nextJob; } - private static function handleOperatorsProcessingFinished(flavorAsset $flavorAsset, flavorParamsOutput $flavorParamsOutput, entry $entry, BatchJob $dbBatchJob, kConvertJobData $data, $rootBatchJob = null) + private static function handleOperatorsProcessingFinished(flavorAsset $flavorAsset, flavorParamsOutput $flavorParamsOutput, entry $entry, BatchJob $dbBatchJob, kConvertJobData $data, $rootBatchJob = null, $syncKey = null) { $offset = $entry->getThumbOffset(); // entry getThumbOffset now takes the partner DefThumbOffset into consideration @@ -886,7 +887,7 @@ private static function handleOperatorsProcessingFinished(flavorAsset $flavorAss if($flavorAsset->getIsOriginal()) $postConvertAssetType = BatchJob::POSTCONVERT_ASSET_TYPE_SOURCE; - kJobsManager::addPostConvertJob($dbBatchJob, $postConvertAssetType, $data->getDestFileSyncLocalPath(), $data->getFlavorAssetId(), $flavorParamsOutput->getId(), $createThumb, $offset); + kJobsManager::addPostConvertJob($dbBatchJob, $postConvertAssetType, $syncKey, $data->getFlavorAssetId(), $flavorParamsOutput->getId(), $createThumb, $offset); } else // no need to run post convert { @@ -1363,7 +1364,7 @@ public static function handleConvertCollectionFinished(BatchJob $dbBatchJob, kCo // creating post convert job (without thumb) $postConvertAssetType = BatchJob::POSTCONVERT_ASSET_TYPE_FLAVOR; - kJobsManager::addPostConvertJob($dbBatchJob, $postConvertAssetType, $flavor->getDestFileSyncLocalPath(), $flavor->getFlavorAssetId(), $flavor->getFlavorParamsOutputId(), file_exists($thumbPath), $offset); + kJobsManager::addPostConvertJob($dbBatchJob, $postConvertAssetType, $syncKey, $flavor->getFlavorAssetId(), $flavor->getFlavorParamsOutputId(), file_exists($thumbPath), $offset); $finalFlavors[] = $flavor; $addedFlavorParamsOutputsIds[] = $flavor->getFlavorParamsOutputId(); @@ -1733,11 +1734,10 @@ public static function handlePostConvertFinished(BatchJob $dbBatchJob, kPostConv $syncKey = $currentFlavorAsset->getSyncKey(flavorAsset::FILE_SYNC_FLAVOR_ASSET_SUB_TYPE_ASSET); if(kFileSyncUtils::fileSync_exists($syncKey)) { - $path = kFileSyncUtils::getLocalFilePathForKey($syncKey); - + $fileSync = kFileSyncUtils::getLocalFileSyncForKey($syncKey, false); $entry = $dbBatchJob->getEntry(); if($entry) - kJobsManager::addConvertProfileJob(null, $entry, $currentFlavorAsset->getId(), $path); + kJobsManager::addConvertProfileJob(null, $entry, $currentFlavorAsset->getId(), $fileSync); } $currentFlavorAsset = null; } diff --git a/alpha/apps/kaltura/lib/batch2/kFlowManager.php b/alpha/apps/kaltura/lib/batch2/kFlowManager.php index db4da2af7be..cf4ab0737f4 100644 --- a/alpha/apps/kaltura/lib/batch2/kFlowManager.php +++ b/alpha/apps/kaltura/lib/batch2/kFlowManager.php @@ -501,19 +501,8 @@ public function objectAdded(BaseObject $object, BatchJob $raisedJob = null) if (kFileSyncUtils::fileSync_exists($syncKey)) { - // Get the asset fileSync. - // For URL typed sync - assume remote and use the relative file path. - // For the other types - use the ordinary kFileSyncUtils::getLocalFilePathForKey. - $fsArr = kFileSyncUtils::getReadyFileSyncForKey($syncKey, true, false); - $fs = $fsArr[0]; - if ($fs && $fs->getFileType() == FileSync::FILE_SYNC_FILE_TYPE_URL) - { - $path = $fs->getFilePath(); - } else - { - $path = kFileSyncUtils::getLocalFilePathForKey($syncKey); - } - kJobsManager::addConvertProfileJob($raisedJob, $entry, $object->getId(), $path); + $fileSync = reset(kFileSyncUtils::getReadyFileSyncForKey($syncKey, true, false)); + kJobsManager::addConvertProfileJob($raisedJob, $entry, $object->getId(), $fileSync); } } @@ -662,10 +651,9 @@ public function objectChanged(BaseObject $object, array $modifiedColumns) $fileSync = kFileSyncUtils::getLocalFileSyncForKey($syncKey, false); if(!$fileSync) return true; - - $srcFileSyncLocalPath = kFileSyncUtils::getLocalFilePathForKey($syncKey); - if($srcFileSyncLocalPath) - kJobsManager::addPostConvertJob(null, $postConvertAssetType, $srcFileSyncLocalPath, $object->getId(), null, $entry->getCreateThumb(), $offset); + + if(kFileSyncUtils::getLocalFilePathForKey($syncKey)) + kJobsManager::addPostConvertJob(null, $postConvertAssetType, $syncKey, $object->getId(), null, $entry->getCreateThumb(), $offset); } elseif ($object->getStatus() == flavorAsset::FLAVOR_ASSET_STATUS_READY) { diff --git a/alpha/apps/kaltura/lib/batch2/kJobsManager.php b/alpha/apps/kaltura/lib/batch2/kJobsManager.php index 00b7c0705c5..4f57ae3e67c 100644 --- a/alpha/apps/kaltura/lib/batch2/kJobsManager.php +++ b/alpha/apps/kaltura/lib/batch2/kJobsManager.php @@ -463,6 +463,7 @@ public static function addFlavorConvertJob(array $srcSyncKeys, flavorParamsOutpu } $partner = PartnerPeer::retrieveByPK($flavorAsset->getPartnerId()); $srcFileSyncs = array(); + $firstValidFileSync = null; foreach ($srcSyncKeys as $srcSyncKey) { @@ -499,19 +500,16 @@ public static function addFlavorConvertJob(array $srcSyncKeys, flavorParamsOutpu $srcFileSyncDescriptor->setAssetParamsId($srcFlavorAsset->getFlavorParamsId()); $srcFileSyncDescriptor->setFileSyncObjectSubType($srcSyncKey->getObjectSubType()); $srcFileSyncs[] = $srcFileSyncDescriptor; + $firstValidFileSync = $firstValidFileSync ? $firstValidFileSync : $fileSync; } } + if (!self::shouldExeConvertJob($firstValidFileSync)) + return null; + // creates convert data $convertData = new kConvertJobData(); $convertData->setSrcFileSyncs($srcFileSyncs); - $sourcePath = $convertData->getSrcFileSyncLocalPath(); - if(kFile::isFileTypeText($sourcePath)) - { - KalturaLog::err("Source file is of type text for flavor id [$flavorAssetId]"); - return null; - } - $convertData->setMediaInfoId($mediaInfoId); $convertData->setFlavorParamsOutputId($flavor->getId()); $convertData->setFlavorAssetId($flavorAssetId); @@ -804,7 +802,7 @@ public static function addCapturaThumbJob(BatchJob $parentJob = null, $partnerId /** * @param BatchJob $parentJob * @param int $postConvertAssetType - * @param string $srcFileSyncLocalPath + * @param FileSyncKey $fileSyncKey * @param int $flavorAssetId * @param int $flavorParamsOutputId * @param bool $createThumb @@ -812,11 +810,11 @@ public static function addCapturaThumbJob(BatchJob $parentJob = null, $partnerId * @param string $customData * @return BatchJob */ - public static function addPostConvertJob(BatchJob $parentJob = null, $postConvertAssetType, $srcFileSyncLocalPath, $flavorAssetId, $flavorParamsOutputId, $createThumb = false, $thumbOffset = 3) + public static function addPostConvertJob(BatchJob $parentJob = null, $postConvertAssetType, $fileSyncKey, $flavorAssetId, $flavorParamsOutputId, $createThumb = false, $thumbOffset = 3) { $postConvertData = new kPostConvertJobData(); $postConvertData->setPostConvertAssetType($postConvertAssetType); - $postConvertData->setSrcFileSyncLocalPath($srcFileSyncLocalPath); + $postConvertData->setSrcFileSyncLocalPath(kFileSyncUtils::getResolveLocalFileSyncForKey($fileSyncKey)); $postConvertData->setFlavorParamsOutputId($flavorParamsOutputId); $postConvertData->setFlavorAssetId($flavorAssetId); $postConvertData->setThumbOffset($thumbOffset); @@ -1212,19 +1210,19 @@ public static function addBulkDownloadJob($partnerId, $puserId, $entryIds, $flav } /** - * @param BatchJob $batchJob + * @param BatchJob $parentJob * @param entry $entry * @param string $flavorAssetId - * @param string $inputFileSyncLocalPath + * @param FileSync $fileSync * @return BatchJob */ - public static function addConvertProfileJob(BatchJob $parentJob = null, entry $entry, $flavorAssetId, $inputFileSyncLocalPath) + public static function addConvertProfileJob(BatchJob $parentJob = null, entry $entry, $flavorAssetId, $fileSync) { - if(kFile::isFileTypeText($inputFileSyncLocalPath)) + if (!self::shouldExeConvertJob($fileSync)) { - KalturaLog::notice('Source of type text will not be converted'); $entry->setStatus(entryStatus::ERROR_CONVERTING); $entry->save(); + myEntryUtils::addTrackEntryInfo($entry,"Source file for conversion is not supported"); return null; } if($entry->getConversionQuality() == conversionProfile2::CONVERSION_PROFILE_NONE) @@ -1235,7 +1233,10 @@ public static function addConvertProfileJob(BatchJob $parentJob = null, entry $e KalturaLog::notice('Entry should not be converted'); return null; } - + + $inputFileSyncLocalPath = $fileSync->getFullPath(); + if ($fileSync->getFileType() == FileSync::FILE_SYNC_FILE_TYPE_URL) + $inputFileSyncLocalPath = $fileSync->getFilePath(); $importingSources = false; // if file size is 0, do not create conversion profile and set entry status as error converting if (!file_exists($inputFileSyncLocalPath) || kFile::fileSize($inputFileSyncLocalPath) == 0) @@ -1389,16 +1390,16 @@ public static function addConvertProfileJob(BatchJob $parentJob = null, entry $e * @param string $entryId * @param int $partnerId * @param StorageProfile $externalStorage - * @param SyncFile $fileSync - * @param string $srcFileSyncLocalPath + * @param FileSync $fileSync + * @param FileSync $srcFileSync * @param bool $force * * @return BatchJob */ - public static function addStorageExportJob(BatchJob $parentJob = null, $entryId, $partnerId, StorageProfile $externalStorage, FileSync $fileSync, $srcFileSyncLocalPath, $force = false, $dc = null) + public static function addStorageExportJob(BatchJob $parentJob = null, $entryId, $partnerId, StorageProfile $externalStorage, FileSync $fileSync, FileSync $srcFileSync, $force = false, $dc = null) { $netStorageExportData = kStorageExportJobData::getInstance($externalStorage->getProtocol()); - $netStorageExportData->setStorageExportJobData($externalStorage, $fileSync, $srcFileSyncLocalPath); + $netStorageExportData->setStorageExportJobData($externalStorage, $fileSync, $srcFileSync); $batchJob = null; if($parentJob) @@ -1782,7 +1783,7 @@ public static function addExportLiveReportJob($reportType, KalturaLiveReportExpo return self::addJob( $job, $jobData, BatchJobType::LIVE_REPORT_EXPORT, $reportType); } - protected static function getFileContainer(FileSyncKey $syncKey) + public static function getFileContainer(FileSyncKey $syncKey) { $fileSync = kFileSyncUtils::getResolveLocalFileSyncForKey($syncKey); @@ -1800,4 +1801,41 @@ protected static function getFileContainerByFileSync(FileSync $fileSync) } return $fileContainer; } + + /** + * @param FileSync $fileSync + * @return bool + */ + private static function shouldExeConvertJob($fileSync) + { + if (!$fileSync) + { + KalturaLog::notice('No file-sync supplied for conversion'); + return false; + } + if (self::shouldBlockFileConversion($fileSync)) + { + KalturaLog::notice('Source of type text will not be converted - FileSyncId [' . $fileSync->getId() . ']'); + return false; + } + return true; + } + + /** + * @param FileSync $fileSync + * @return bool + */ + private static function shouldBlockFileConversion($fileSync) + { + if($fileSync->isEncrypted()) + $filePath = $fileSync->createTempClear(); + else + $filePath = $fileSync->getFullPath(); + $actualFileDescription = trim(kFile::getFileDescription($filePath)); + $blackList = kconf::get('file_descriptions_black_list'); + $shouldBlock = in_array($actualFileDescription,$blackList['fileDescriptions']); + if($fileSync->isEncrypted()) + $fileSync->deleteTempClear(); + return $shouldBlock; + } } diff --git a/alpha/apps/kaltura/lib/batch2/model/kAmazonS3StorageExportJobData.php b/alpha/apps/kaltura/lib/batch2/model/kAmazonS3StorageExportJobData.php index 46b3f114084..9f94f22d1f5 100644 --- a/alpha/apps/kaltura/lib/batch2/model/kAmazonS3StorageExportJobData.php +++ b/alpha/apps/kaltura/lib/batch2/model/kAmazonS3StorageExportJobData.php @@ -35,9 +35,9 @@ class kAmazonS3StorageExportJobData extends kStorageExportJobData */ private $endPoint; - public function setStorageExportJobData(StorageProfile $externalStorage, FileSync $fileSync, $srcFileSyncLocalPath, $force = false) + public function setStorageExportJobData(StorageProfile $externalStorage, FileSync $fileSync, $srcFileSync, $force = false) { - parent::setStorageExportJobData($externalStorage, $fileSync, $srcFileSyncLocalPath); + parent::setStorageExportJobData($externalStorage, $fileSync, $srcFileSync); $this->setFilesPermissionInS3($externalStorage->getFilesPermissionInS3()); $this->setS3Region($externalStorage->getS3Region()); $this->setSseType($externalStorage->getSseType()); diff --git a/alpha/apps/kaltura/lib/batch2/model/kConvartableJobData.php b/alpha/apps/kaltura/lib/batch2/model/kConvartableJobData.php index 68130394730..58d2132aa75 100644 --- a/alpha/apps/kaltura/lib/batch2/model/kConvartableJobData.php +++ b/alpha/apps/kaltura/lib/batch2/model/kConvartableJobData.php @@ -151,21 +151,21 @@ public function setFlavorParamsOutput($flavorParamsOutput) } /** - * @param $srcFileSyncLocalPath the $srcFileSyncLocalPath to set + * @param FileSync $fileSync */ - public function setSrcFileSyncLocalPath($srcFileSyncLocalPath) + public function setSrcFileSyncLocalPath($fileSync) { $srcDescriptor = (is_array($this->srcFileSyncs) && count($this->srcFileSyncs) ? reset($this->srcFileSyncs) : null); if(!$srcDescriptor) { $srcDescriptor = new kSourceFileSyncDescriptor(); - $srcDescriptor->setFileSyncLocalPath($srcFileSyncLocalPath); + $srcDescriptor->setPathAndKeyByFileSync($fileSync); $this->srcFileSyncs = array($srcDescriptor); } else { - $srcDescriptor->setFileSyncLocalPath($srcFileSyncLocalPath); + $srcDescriptor->setPathAndKeyByFileSync($fileSync); } } diff --git a/alpha/apps/kaltura/lib/batch2/model/kStorageExportJobData.php b/alpha/apps/kaltura/lib/batch2/model/kStorageExportJobData.php index 3b7a95371c8..1231580c586 100644 --- a/alpha/apps/kaltura/lib/batch2/model/kStorageExportJobData.php +++ b/alpha/apps/kaltura/lib/batch2/model/kStorageExportJobData.php @@ -33,7 +33,7 @@ public static function getInstance($protocol) return $data; } - public function setStorageExportJobData(StorageProfile $externalStorage, FileSync $fileSync, $srcFileSyncLocalPath, $force = false) + public function setStorageExportJobData(StorageProfile $externalStorage, FileSync $fileSync, FileSync $srcFileSync, $force = false) { $this->setServerUrl($externalStorage->getStorageUrl()); $this->setServerUsername($externalStorage->getStorageUsername()); @@ -42,7 +42,8 @@ public function setStorageExportJobData(StorageProfile $externalStorage, FileSyn $this->setServerPublicKey($externalStorage->getPublicKey()); $this->setServerPassPhrase($externalStorage->getPassPhrase()); $this->setFtpPassiveMode($externalStorage->getStorageFtpPassiveMode()); - $this->setSrcFileSyncLocalPath($srcFileSyncLocalPath); + $this->setSrcFileSyncLocalPath($srcFileSync->getFullPath()); + $this->setSrcFileEncryptionKey($srcFileSync->getEncryptionKey()); $this->setSrcFileSyncId($fileSync->getId()); $this->setForce($force); $this->setDestFileSyncStoredPath($externalStorage->getStorageBaseDir() . '/' . $fileSync->getFilePath()); diff --git a/alpha/apps/kaltura/lib/batch2/model/kStorageJobData.php b/alpha/apps/kaltura/lib/batch2/model/kStorageJobData.php index 7a31d1e8515..fc62e5385cf 100644 --- a/alpha/apps/kaltura/lib/batch2/model/kStorageJobData.php +++ b/alpha/apps/kaltura/lib/batch2/model/kStorageJobData.php @@ -45,6 +45,11 @@ class kStorageJobData extends kJobData */ private $srcFileSyncLocalPath; + /** + * @var string + */ + private $srcFileEncryptionKey; + /** * @var string */ @@ -95,6 +100,14 @@ public function getSrcFileSyncLocalPath() return $this->srcFileSyncLocalPath; } + /** + * @return string $srcFileSyncLocalPath + */ + public function getSrcFileEncryptionKey() + { + return $this->srcFileEncryptionKey; + } + /** * @return the $srcFileSyncId */ @@ -143,6 +156,14 @@ public function setSrcFileSyncLocalPath($srcFileSyncLocalPath) $this->srcFileSyncLocalPath = $srcFileSyncLocalPath; } + /** + * @param string $srcFileEncryptionKey to set + */ + public function setSrcFileEncryptionKey($srcFileEncryptionKey) + { + $this->srcFileEncryptionKey = $srcFileEncryptionKey; + } + /** * @param $srcFileSyncId the $srcFileSyncId to set */ diff --git a/alpha/apps/kaltura/lib/dateUtils.class.php b/alpha/apps/kaltura/lib/dateUtils.class.php index e70e9fbb298..3ee3188d89e 100644 --- a/alpha/apps/kaltura/lib/dateUtils.class.php +++ b/alpha/apps/kaltura/lib/dateUtils.class.php @@ -119,5 +119,12 @@ public static function isWithinTimeFrame($absolute_time_in_sec, $relative_start_ } + public static function diffInDays ($date1, $date2) + { + $date1 = new DateTime($date1); + $date2 = new DateTime($date2); + $diff = $date2->diff($date1)->format("%a"); + return $diff; + } } ?> \ No newline at end of file diff --git a/alpha/apps/kaltura/lib/kAssetPropertiesManager.php b/alpha/apps/kaltura/lib/kAssetPropertiesManager.php index 044cb5af930..9bd081b1a87 100644 --- a/alpha/apps/kaltura/lib/kAssetPropertiesManager.php +++ b/alpha/apps/kaltura/lib/kAssetPropertiesManager.php @@ -7,11 +7,17 @@ class kAssetPropertiesManager implements kObjectChangedEventConsumer */ public function shouldConsumeChangedEvent(BaseObject $object, array $modifiedColumns) { + $propertiesListToHandle = array ('language','label','default'); if($object instanceof asset) { - if (in_array(assetPeer::CUSTOM_DATA, $modifiedColumns) && - ($object->isCustomDataModified('language') || $object->isCustomDataModified('label'))) - return true; + if (in_array(assetPeer::CUSTOM_DATA, $modifiedColumns)) + { + foreach($propertiesListToHandle as $propertyItem) + { + if($object->isCustomDataModified($propertyItem)) + return true; + } + } } return false; } diff --git a/alpha/apps/kaltura/lib/model/objectfilters/entryFilter.class.php b/alpha/apps/kaltura/lib/model/objectfilters/entryFilter.class.php index 7ac2f66da15..f18b320f6c8 100644 --- a/alpha/apps/kaltura/lib/model/objectfilters/entryFilter.class.php +++ b/alpha/apps/kaltura/lib/model/objectfilters/entryFilter.class.php @@ -22,7 +22,7 @@ public function setSwitchUserIdToKuserId( $kuser_id ) private static $relative_time_fields = array("gte_created_at","lte_created_at","gte_updated_at","lte_updated_at","gte_last_played_at","lte_last_played_at","gte_media_date","lte_media_date","lteornull_start_date","gteornull_start_date","lte_start_date","gte_start_date","lteornull_end_date","gteornull_end_date","lte_end_date","gte_end_date"); - public function init () + protected function init () { // TODO - should separate the schema of the fields from the actual values // or can use this to set default valuse diff --git a/alpha/apps/kaltura/lib/model/objectfilters/filters.class.php b/alpha/apps/kaltura/lib/model/objectfilters/filters.class.php index c37ab5bc785..e6c23f952fb 100644 --- a/alpha/apps/kaltura/lib/model/objectfilters/filters.class.php +++ b/alpha/apps/kaltura/lib/model/objectfilters/filters.class.php @@ -10,7 +10,8 @@ abstract class baseObjectFilter extends myBaseObject { public $fields; - + protected $fieldsToIgnoreInFinalCriteria; + protected static $maxInValues = 500; /** @@ -196,6 +197,12 @@ public function __construct ( $field_name_translation_type = BasePeer::TYPE_FIEL return $res; } + protected function init() + { + parent::init(); + $this->InitFieldsToIgnoreInFinalCriteria(); + } + function __sleep() { $allVars = get_object_vars($this); @@ -586,8 +593,8 @@ public function attachToFinalCriteria ( Criteria $criteria ) if ( $pos === 0 ) { - if ( $field == self::ORDER ) continue; - if ( $field == self::LIMIT ) continue; + if( in_array($field, $this->getFieldsToIgnoreInFinalCriteria()) ) + continue; // this is the case of a 'auto-named-field' - the prefix indicates the type of the criterion $end_of_prefix_index = strpos ( $field , baseObjectFilter::FILTER_PREFIX , 1) + 1; @@ -1020,5 +1027,33 @@ public function fillObjectFromXml ( SimpleXMLElement $simple_xml_node , $prefix_ return $set_field_count; } + + /** + * @param string $fieldName + */ + protected function addFieldToIgnoreInFinalCriteria($fieldName) + { + $fields = $this->getFieldsToIgnoreInFinalCriteria(); + $fields[] = $fieldName; + $this->setFieldToIgnoreInFinalCriteria($fields); + } + + protected function getFieldsToIgnoreInFinalCriteria() + { + if(empty($this->fieldsToIgnoreInFinalCriteria)) + $this->InitFieldsToIgnoreInFinalCriteria(); + + return $this->fieldsToIgnoreInFinalCriteria; + } + + protected function InitFieldsToIgnoreInFinalCriteria() + { + $this->fieldsToIgnoreInFinalCriteria = array(self::ORDER, self::LIMIT); + } + + private function setFieldToIgnoreInFinalCriteria($fields) + { + $this->fieldsToIgnoreInFinalCriteria = $fields; + } } ?> diff --git a/alpha/apps/kaltura/lib/model/objectfilters/mediaEntryFilterForPlaylist.php b/alpha/apps/kaltura/lib/model/objectfilters/mediaEntryFilterForPlaylist.php new file mode 100644 index 00000000000..76040bde718 --- /dev/null +++ b/alpha/apps/kaltura/lib/model/objectfilters/mediaEntryFilterForPlaylist.php @@ -0,0 +1,27 @@ +fields = array_merge($this->fields , $extendedFields); + $this->InitFieldsToIgnoreInFinalCriteria(); + } + + protected function InitFieldsToIgnoreInFinalCriteria() + { + parent::InitFieldsToIgnoreInFinalCriteria(); + $this->addFieldToIgnoreInFinalCriteria(self::NAME); + } +} \ No newline at end of file diff --git a/alpha/apps/kaltura/lib/myEntryUtils.class.php b/alpha/apps/kaltura/lib/myEntryUtils.class.php index a07377c4d39..e9d7380f40f 100644 --- a/alpha/apps/kaltura/lib/myEntryUtils.class.php +++ b/alpha/apps/kaltura/lib/myEntryUtils.class.php @@ -786,6 +786,10 @@ public static function resizeEntryImage( entry $entry, $version , $width , $heig while($count--) { + $thumbCaptureByPackager = false; + $forceRotation = ($vid_slices > -1) ? self::getRotate($flavorAssetId) : 0; + $params = array($density, $quality, $forceRotation, $src_x, $src_y, $src_w, $src_h, $stripProfiles); + $shouldResizeByPackager = self::shouldResizeByPackager($params, $type, array($width, $height)); if ( // need to create a thumb if either: // 1. entry is a video and a specific second was requested OR a slices were requested @@ -831,9 +835,14 @@ public static function resizeEntryImage( entry $entry, $version , $width , $heig $success = false; if($multi && $packagerRetries) { - $success = self::captureThumbUsingPackager($entry, $capturedThumbPath, $calc_vid_sec, $flavorAssetId); + list($picWidth, $picHeight) = $shouldResizeByPackager ? array($width, $height) : array(null, null); + $destPath = $shouldResizeByPackager ? $capturedThumbPath . uniqid() : $capturedThumbPath; + $success = self::captureThumbUsingPackager($entry, $destPath, $calc_vid_sec, $flavorAssetId, $picWidth, $picHeight); + $packagerResizeFullPath = $destPath . self::TEMP_FILE_POSTFIX; + KalturaLog::debug("Packager capture is [$success] with dimension [$picWidth,$picHeight] and packagerResize [$shouldResizeByPackager] in path [$packagerResizeFullPath]"); if(!$success) $packagerRetries--; + $thumbCaptureByPackager = $success; } if (!$success) @@ -861,9 +870,7 @@ public static function resizeEntryImage( entry $entry, $version , $width , $heig // close db connections as we won't be requiring the database anymore and image manipulation may take a long time kFile::closeDbConnections(); - - $forceRotation = ($vid_slices > -1) ? self::getRotate($flavorAssetId) : 0; - + if (!self::isTempFile($orig_image_path) && $isEncryptionNeeded) { $orig_image_path = $fileSync->createTempClear(); //will be deleted after the conversion @@ -872,26 +879,36 @@ public static function resizeEntryImage( entry $entry, $version , $width , $heig kFile::fullMkdir($processingThumbPath); - if ($crop_provider) + if ($thumbCaptureByPackager && $shouldResizeByPackager) { - $convertedImagePath = myFileConverter::convertImageUsingCropProvider($orig_image_path, $processingThumbPath, $width, $height, $type, $crop_provider, $bgcolor, true, $quality, $src_x, $src_y, $src_w, $src_h, $density, $stripProfiles,$forceRotation); + $processingThumbPath = $packagerResizeFullPath; + $convertedImagePath = $packagerResizeFullPath; + KalturaLog::debug("Image was resize in the packager - setting path [$processingThumbPath]"); } - else + else //need to crop the image { - if (!file_exists($orig_image_path) || !filesize($orig_image_path)) - KExternalErrors::dieError(KExternalErrors::IMAGE_RESIZE_FAILED); - - $imageSizeArray = getimagesize($orig_image_path); - if ($thumbParams->getSupportAnimatedThumbnail() && is_array($imageSizeArray) && $imageSizeArray[2] === IMAGETYPE_GIF) + if ($crop_provider) { - $processingThumbPath = kFile::replaceExt($processingThumbPath, "gif"); - $finalThumbPath = kFile::replaceExt($finalThumbPath, "gif"); + $convertedImagePath = myFileConverter::convertImageUsingCropProvider($orig_image_path, $processingThumbPath, $width, $height, $type, $crop_provider, $bgcolor, true, $quality, $src_x, $src_y, $src_w, $src_h, $density, $stripProfiles,$forceRotation); } + else + { + if (!file_exists($orig_image_path) || !filesize($orig_image_path)) + KExternalErrors::dieError(KExternalErrors::IMAGE_RESIZE_FAILED); - $convertedImagePath = myFileConverter::convertImage($orig_image_path, $processingThumbPath, $width, $height, $type, $bgcolor, true, $quality, $src_x, $src_y, $src_w, $src_h, $density, $stripProfiles, $thumbParams, $format,$forceRotation); + $imageSizeArray = getimagesize($orig_image_path); + if ($thumbParams->getSupportAnimatedThumbnail() && is_array($imageSizeArray) && $imageSizeArray[2] === IMAGETYPE_GIF) + { + $processingThumbPath = kFile::replaceExt($processingThumbPath, "gif"); + $finalThumbPath = kFile::replaceExt($finalThumbPath, "gif"); + } + + $convertedImagePath = myFileConverter::convertImage($orig_image_path, $processingThumbPath, $width, $height, $type, $bgcolor, true, $quality, $src_x, $src_y, $src_w, $src_h, $density, $stripProfiles, $thumbParams, $format,$forceRotation); + } } + // die if resize operation failed if ($convertedImagePath === null || !@filesize($convertedImagePath)) { KExternalErrors::dieError(KExternalErrors::IMAGE_RESIZE_FAILED); @@ -908,10 +925,13 @@ public static function resizeEntryImage( entry $entry, $version , $width , $heig ++$vid_slice; } + if ($thumbCaptureByPackager && $shouldResizeByPackager) + unlink($packagerResizeFullPath); + if ($isEncryptionNeeded) { $fileSync->deleteTempClear(); - if (self::isTempFile($orig_image_path)) + if (self::isTempFile($orig_image_path) && file_exists($orig_image_path)) unlink($orig_image_path); } } @@ -2075,4 +2095,21 @@ private static function curlLocalVolumeMapUrl($url, $packagerVolumeMapUrlPattern return $content; } + private static function shouldResizeByPackager($params, $type, $dimension) + { + //check if all null or 0 + $canBeHandle = (count(array_filter($params)) == 0); + // check if only one dimension is given or type 5 (stretches to the exact dimensions) + $positiveDimension = array_filter($dimension, function ($v) {return $v > 0;}); + $validDimension = ($type == 5) || (count($positiveDimension) == 1); + return ($canBeHandle && $validDimension); + } + + public static function addTrackEntryInfo(entry $entry,$message) + { + $trackEntry = new TrackEntry(); + $trackEntry->setEntryId($entry->getId()); + $trackEntry->setDescription($message); + TrackEntry::addTrackEntry($trackEntry); + } } diff --git a/alpha/apps/kaltura/lib/myPartnerUtils.class.php b/alpha/apps/kaltura/lib/myPartnerUtils.class.php index 958883b2a00..d2cbbada5e6 100644 --- a/alpha/apps/kaltura/lib/myPartnerUtils.class.php +++ b/alpha/apps/kaltura/lib/myPartnerUtils.class.php @@ -12,7 +12,9 @@ class myPartnerUtils const ALL_PARTNERS_WILD_CHAR = "*"; const BLOCKING_DAYS_GRACE = 7; - + + const FREE_TRIAL_END_DAY = 30; + const FREE_TRIAL_PARTNER_DELETION_DAY = 60; private static $s_current_partner_id = null; private static $s_set_partner_id_policy = self::PARTNER_SET_POLICY_NONE; @@ -1088,7 +1090,11 @@ public static function doPartnerUsage(Partner $partner) $packages = new PartnerPackages(); $partnerPackage = $packages->getPackageDetails($partner->getPartnerPackage()); - + + $monitoredFreeTrial = false; + if(myPartnerUtils::isPartnerCreatedAsMonitoredFreeTrial($partner)) + $monitoredFreeTrial = true; + $report_date = date('Y-m').'-01'; // We are now working with the DWH and a stored-procedure, and not with record type 6 on partner_activity. $report_date = dateUtils::todayOffset(-1); @@ -1096,6 +1102,7 @@ public static function doPartnerUsage(Partner $partner) list ( $totalStorage , $totalUsage , $totalTraffic ) = myPartnerUtils::collectPartnerStatisticsFromDWH($partner, $partnerPackage, $report_date); $totalUsageGB = $totalUsage/1024/1024; // from KB to GB $percent = round( ($totalUsageGB / $partnerPackage['cycle_bw'])*100, 2); + $partner->setPartnerUsagePercent($percent); KalturaLog::debug("percent (".$partner->getId().") is: $percent"); $email_link_hash = 'pid='.$partner->getId().'&h='.(self::getEmailLinkHash($partner->getId(), $partner->getSecret())); @@ -1115,8 +1122,11 @@ public static function doPartnerUsage(Partner $partner) /* prepare mail job, and set EightyPercentWarning() to true/date */ $partner->setEightyPercentWarning(time()); $partner->setUsageLimitWarning(0); - $body_params = array ( $partner->getAdminName(), $partnerPackage['cycle_bw'], $mindtouch_notice, round($totalUsageGB, 2), $email_link_hash ); - myPartnerUtils::notifiyPartner(myPartnerUtils::KALTURA_PACKAGE_EIGHTY_PERCENT_WARNING, $partner, $body_params); + if(!$monitoredFreeTrial) + { + $body_params = array($partner->getAdminName(), $partnerPackage['cycle_bw'], $mindtouch_notice, round($totalUsageGB, 2), $email_link_hash); + myPartnerUtils::notifiyPartner(myPartnerUtils::KALTURA_PACKAGE_EIGHTY_PERCENT_WARNING, $partner, $body_params); + } } elseif ($percent >= 80 && $percent < 100 && @@ -1137,15 +1147,23 @@ public static function doPartnerUsage(Partner $partner) elseif ($percent >= 100 && !$partner->getUsageLimitWarning()) { - KalturaLog::debug("partner ". $partner->getId() ." reached 100% - setting second warning"); - /* prepare mail job, and set getUsageLimitWarning() date */ $partner->setUsageLimitWarning(time()); // if ($partnerPackage['cycle_fee'] == 0) - script always works on free partners anyway + if(!$monitoredFreeTrial) { + KalturaLog::debug("partner ". $partner->getId() ." reached 100% - setting second warning"); $body_params = array ( $partner->getAdminName(), $mindtouch_notice, round($totalUsageGB, 2), $email_link_hash ); myPartnerUtils::notifiyPartner(myPartnerUtils::KALTURA_PACKAGE_LIMIT_WARNING_1, $partner, $body_params); } + else + { + KalturaLog::debug("partner ". $partner->getId() ." reached 100% - blocking partner"); + if($should_block_delete_partner) + { + $partner->setStatus(Partner::PARTNER_STATUS_CONTENT_BLOCK); + } + } } elseif ($percent >= 100 && $partnerPackage['cycle_fee'] == 0 && @@ -1166,7 +1184,8 @@ public static function doPartnerUsage(Partner $partner) } elseif ($percent >= 120 && $partnerPackage['cycle_fee'] != 0 && - $partner->getUsageLimitWarning() <= $block_notification_grace) + $partner->getUsageLimitWarning() <= $block_notification_grace && + !$monitoredFreeTrial) { $body_params = array ( $partner->getAdminName(), round($totalUsageGB, 2) ); myPartnerUtils::notifiyPartner(myPartnerUtils::KALTURA_PAID_PACKAGE_SUGGEST_UPGRADE, $partner, $body_params); @@ -1175,7 +1194,8 @@ public static function doPartnerUsage(Partner $partner) $partnerPackage['cycle_fee'] == 0 && $partner->getUsageLimitWarning() > 0 && $partner->getUsageLimitWarning() <= $delete_grace && - $partner->getStatus() == Partner::PARTNER_STATUS_CONTENT_BLOCK) + $partner->getStatus() == Partner::PARTNER_STATUS_CONTENT_BLOCK && + !$monitoredFreeTrial) { KalturaLog::debug("partner ". $partner->getId() ." reached 100% a month ago - deleting partner"); @@ -1450,6 +1470,8 @@ public static function copyTemplateContent(Partner $fromPartner, Partner $toPart self::copyUiConfsByType($fromPartner, $toPartner, uiConf::UI_CONF_TYPE_WIDGET); self::copyUiConfsByType($fromPartner, $toPartner, uiConf::UI_CONF_TYPE_KDP3); + self::saveTemplateObjectsNum($fromPartner, $toPartner); + // Launch a batch job that will copy the heavy load as an async operation kJobsManager::addCopyPartnerJob( $fromPartner->getId(), $toPartner->getId() ); } @@ -1831,4 +1853,235 @@ public static function getWhiteListHost(Partner $partner) } return null; } + + /** + * The function checks for new free trial partners if its time to block/delete them and whether + * we need to sync their lead in Marketo + * + * @param partner $partner + */ + public static function handleDayInFreeTrial(Partner $partner) + { + $dayInFreeTrial = dateUtils::diffInDays($partner->getCreatedAt(), dateUtils::today()); + KalturaLog::debug("partner [{$partner->getId()}] is currently at the [$dayInFreeTrial] day of free trial"); + + if (($dayInFreeTrial >= self::FREE_TRIAL_END_DAY) && ($dayInFreeTrial < self::FREE_TRIAL_PARTNER_DELETION_DAY)) + { + KalturaLog::debug('Partner ['.$partner->getId().'] reached to end of free trial day. Blocking content.'); + $partner->setStatus(Partner::PARTNER_STATUS_CONTENT_BLOCK); + } + + if ($dayInFreeTrial >= self::FREE_TRIAL_PARTNER_DELETION_DAY) + { + KalturaLog::debug('Partner ['.$partner->getId().'] reached to free trial deletion day. Deleting partner.'); + $partner->setStatus(Partner::PARTNER_STATUS_DELETED); + } + + $freeTrialUpdatesDays = kConf::get('free_trial_updates_days'); + $closestUpdatesDay = self::getClosestDay($dayInFreeTrial, $freeTrialUpdatesDays); + KalturaLog::debug('closest day comparing today ['.$closestUpdatesDay.']'); + if ($closestUpdatesDay > $partner->getLastFreeTrialNotificationDay()) + { + KalturaLog::debug('Partner ['.$partner->getId().'] reached to one of the Marketo lead sync days.'); + $partner->setLastFreeTrialNotificationDay($dayInFreeTrial); + } + + $partner->save(); + } + + /** + * retrieve the closest (lowest) notification day compering today + * + * @param int $search + * @param array $arr + * @return int + */ + public static function getClosestDay($search, $arr) { + $closest = 0; + foreach ($arr as $item) + { + if (($item <= $search) && (abs($search - $closest) > abs($item - $search))) + $closest = $item; + } + return $closest; + } + + + /** + * save in partner's custom data the number of objects from different type that were created + * as part of the partner population from template partner + * + * @param partner $fromPartner + * @param partner $toPartner + */ + public static function saveTemplateObjectsNum(Partner $fromPartner, Partner $toPartner) + { + KalturaLog::log('Saving the number of entries, categories and metadata objects exist on partner ['.$fromPartner->getId().'] on partner ['.$toPartner->getId().']'); + $fromPartnerId = $fromPartner->getId(); + + $categoriesNum = self::getCategoriesNumForPartner($fromPartnerId); + $toPartner->setTemplateCategoriesNum($categoriesNum); + + $entriesNum = self::getEntriesNumForPartner($fromPartnerId); + $toPartner->setTemplateEntriesNum($entriesNum); + + $metadataNum = self::getMetadataObjectsNumForPartner($fromPartnerId); + $toPartner->setTemplateCustomMetadataNum($metadataNum); + + $toPartner->save(); + } + + /** + * calculate the number of categories using partner and status + * + * @param string $partnerId + * @param bool $onlyActive + * @return int $categoriesNum + */ + public static function getCategoriesNumForPartner($partnerId, $onlyActive = true) + { + categoryPeer::setUseCriteriaFilter(false); + $c = new Criteria(); + $c->addAnd(categoryPeer::PARTNER_ID, $partnerId); + if($onlyActive) + $c->addAnd(categoryPeer::STATUS, CategoryStatus::ACTIVE); + $categoriesNum = categoryPeer::doCount($c); + categoryPeer::setUseCriteriaFilter(true); + return $categoriesNum; + } + + /** + * calculate the number of entries using partner and status + * + * @param string $partnerId + * @param bool $onlyReady + * @return int $entriesNum + */ + public static function getEntriesNumForPartner($partnerId, $onlyReady = true) + { + entryPeer::setUseCriteriaFilter(false); + $c = new Criteria(); + $c->addAnd(entryPeer::PARTNER_ID, $partnerId); + if($onlyReady) + $c->addAnd(entryPeer::STATUS, entryStatus::READY); + $entriesNum = entryPeer::doCount($c); + entryPeer::setUseCriteriaFilter(true); + return $entriesNum; + } + + /** + * calculate the number of custome metadata objects using partner and status + * + * @param string $partnerId + * @param bool $onlyValid + * @return int $metadataNum + */ + public static function getMetadataObjectsNumForPartner($partnerId, $onlyValid = true) + { + MetadataPeer::setUseCriteriaFilter(false); + $c = new Criteria(); + $c->addAnd(metadataPeer::PARTNER_ID, $partnerId); + if($onlyValid) + $c->addAnd(MetadataPeer::STATUS, Metadata::STATUS_VALID); + $metadataNum = MetadataPeer::doCount($c); + MetadataPeer::setUseCriteriaFilter(true); + return $metadataNum; + } + + /** + * calculate the number of categories that the partner created after the account population + * (exclude objects that were from template partner) + * + * @param partner $partner + * @return int $partnerCategories + */ + public static function getNumOfCategoriesCreatedByPartner ($partner) + { + $partnerId = $partner->getId(); + $categories = self::getCategoriesNumForPartner($partnerId, false); + $partnerCategories = $categories - $partner->getTemplateCategoriesNum(); + return $partnerCategories; + } + + /** + * calculate the number of entries that the partner created after the account population + * (exclude objects that were from template partner) + * + * @param partner $partner + * @return int $partnerEntries + */ + public static function getNumOfEntriesCreatedByPartner ($partner) + { + $partnerId = $partner->getId(); + $entries = self::getEntriesNumForPartner($partnerId, false); + $partnerEntries = $entries - $partner->getTemplateEntriesNum(); + return $partnerEntries; + } + + /** + * calculate the number of custom metadata objects that the partner created after the account population + * (exclude objects that were from template partner) + * + * @param partner $partner + * @return int $partnerMetadata + */ + public static function getNumOfMetadataObjectsCreatedByPartner ($partner) + { + $partnerId = $partner->getId(); + $MetadataObjects = self::getMetadataObjectsNumForPartner($partnerId, false); + $partnerMetadata = $MetadataObjects - $partner->getTemplateCustomMetadataNum(); + return $partnerMetadata; + } + + + /** + * calculate the partner percent usage + * + * @param partner $partner + * @return int $percent + */ + public static function retrievePartnerUsagePercent($partner) + { + $packages = new PartnerPackages(); + $partnerPackage = $packages->getPackageDetails($partner->getPartnerPackage()); + $report_date = date('Y-m').'-01'; + list ( $totalStorage , $totalUsage , $totalTraffic ) = myPartnerUtils::collectPartnerStatisticsFromDWH($partner, $partnerPackage, $report_date); + $totalUsageGB = $totalUsage/1024/1024; // from KB to GB + $percent = round( ($totalUsageGB / $partnerPackage['cycle_bw'])*100, 2); + return $percent; + } + + + /** + * calculate the number of entries that were changed after creation + * + * @param entry $entry + */ + public static function increaseEntriesChangedNum($entry) + { + $partner = PartnerPeer::retrieveByPK($entry->getPartnerId()); + if ($partner->getPartnerPackage() == PartnerPackages::PARTNER_PACKAGE_FREE) + { + $entriesNum = $partner->getEntriesChangedByPartnerNum() + 1; + $partner->setEntriesChangedByPartnerNum($entriesNum); + $partner->save(); + } + + } + + /** + * check if partner was created after we started the new free trial flow + * + * @param partner $partner + * @return bool + */ + public static function isPartnerCreatedAsMonitoredFreeTrial($partner) + { + $freeTrialStartDate = kConf::get('new_free_trial_start_date','local', null); + if(!$freeTrialStartDate) + return false; + if($partner->getCreatedAt() >= $freeTrialStartDate) + return true; + return false; + } } diff --git a/alpha/apps/kaltura/lib/reports/kKavaLiveReportsMgr.class.php b/alpha/apps/kaltura/lib/reports/kKavaLiveReportsMgr.class.php index 76e119838f7..2129771b2c5 100644 --- a/alpha/apps/kaltura/lib/reports/kKavaLiveReportsMgr.class.php +++ b/alpha/apps/kaltura/lib/reports/kKavaLiveReportsMgr.class.php @@ -2,7 +2,9 @@ class kKavaLiveReportsMgr extends kKavaBase { - const MAX_RESULTS = 1000; + const MIN_RESULTS = 1000; + const MAX_RESULTS = 10000; + const MAX_LIVE_ENTRIES = 1000; const PEAK_AUDIENCE_MAX_BUCKETS = 1000; // intermediate metrics @@ -24,6 +26,11 @@ class kKavaLiveReportsMgr extends kKavaBase const OUTPUT_PLAYS = 'plays'; const OUTPUT_REFERRER = 'referrer'; + protected static function getLimit($limit) + { + return max(min($limit, self::MAX_RESULTS), self::MIN_RESULTS); + } + protected static function getLiveEntries($partnerId, $entryIds, $isLive) { $filter = new entryFilter(); @@ -40,7 +47,7 @@ protected static function getLiveEntries($partnerId, $entryIds, $isLive) $criteria = KalturaCriteria::create(entryPeer::OM_CLASS); $criteria->addAscendingOrderByColumn(entryPeer::NAME); // Note: don't really care about order here, this is a hack to force the query to go to sphinx - $criteria->setLimit(self::MAX_RESULTS); + $criteria->setLimit(self::MAX_LIVE_ENTRIES); $filter->attachToCriteria($criteria); $criteria->applyFilters(); @@ -56,6 +63,7 @@ protected static function sortByEntryName($input) $criteria = KalturaCriteria::create(entryPeer::OM_CLASS); $criteria->add(entryPeer::ID, array_keys($input), Criteria::IN); + $criteria->add(entryPeer::TYPE, entryType::LIVE_STREAM); $criteria->addAscendingOrderByColumn(entryPeer::NAME); $criteria->applyFilters(); $orderedIds = $criteria->getFetchedIds(); @@ -113,7 +121,7 @@ protected static function getBaseFilter($partnerId, $eventTypes, $filter) protected static function getFilterIntervals($filter) { $fromTime = $filter->fromTime; - $toTime = max($filter->fromTime + self::VIEW_EVENT_INTERVAL, $filter->toTime); + $toTime = $filter->toTime + self::VIEW_EVENT_INTERVAL; return self::getIntervals($fromTime, $toTime); } @@ -144,7 +152,7 @@ protected static function getBaseTimeseriesQuery($partnerId, $filter, $eventType ); } - protected static function getBaseTopNQuery($partnerId, $filter, $eventTypes, $dimension, $metric) + protected static function getBaseTopNQuery($partnerId, $filter, $eventTypes, $dimension, $metric, $threshold) { return array( self::DRUID_QUERY_TYPE => self::DRUID_TOPN, @@ -153,7 +161,7 @@ protected static function getBaseTopNQuery($partnerId, $filter, $eventTypes, $di self::DRUID_FILTER => self::getBaseFilter($partnerId, $eventTypes, $filter), self::DRUID_DIMENSION => $dimension, self::DRUID_METRIC => $metric, - self::DRUID_THRESHOLD => self::MAX_RESULTS, + self::DRUID_THRESHOLD => $threshold, ); } @@ -255,18 +263,18 @@ protected static function updateBaseFields(&$dest, $src) self::OUTPUT_PLAYS, self::OUTPUT_AVG_BITRATE, self::OUTPUT_AUDIENCE, - self::OUTPUT_DVR_AUDIENCE, - self::OUTPUT_BUFFER_TIME); + self::OUTPUT_DVR_AUDIENCE); foreach ($fieldNames as $fieldName) { $dest[$fieldName] = $src[$fieldName]; } + $dest[self::OUTPUT_BUFFER_TIME] = $src[self::OUTPUT_BUFFER_TIME] * 6; // return in minutes $dest[self::OUTPUT_SEC_VIEWED] = $src[self::METRIC_VIEW_COUNT] * self::VIEW_EVENT_INTERVAL; } // reports - public static function partnerTotal($partnerId, $filter) + public static function partnerTotal($partnerId, $filter, $limit) { // view events $query = self::getBaseTimeseriesQuery($partnerId, $filter, null); @@ -279,7 +287,7 @@ public static function partnerTotal($partnerId, $filter) return array($result); } - public static function entryTotal($partnerId, $filter) + public static function entryTotal($partnerId, $filter, $limit) { // view events $query = self::getBaseTopNQuery( @@ -287,7 +295,8 @@ public static function entryTotal($partnerId, $filter) $filter, null, self::DIMENSION_ENTRY_ID, - self::METRIC_VIEW_COUNT); + self::METRIC_VIEW_COUNT, + self::getLimit($limit)); self::addBaseAggregations($query); $queryResult = self::runGranularityAllQuery($query); @@ -309,7 +318,8 @@ public static function entryTotal($partnerId, $filter) $filter, array(self::EVENT_TYPE_VIEW), self::DIMENSION_ENTRY_ID, - self::METRIC_VIEW_COUNT); + self::METRIC_VIEW_COUNT, + self::getLimit($limit)); $query[self::DRUID_AGGR] = array( self::getViewCountAggregator(), self::getAudienceAggregator(), @@ -352,15 +362,16 @@ public static function entryTotal($partnerId, $filter) return $result; } - - public static function entrySyndicationTotal($partnerId, $filter) + + public static function entrySyndicationTotal($partnerId, $filter, $limit) { $query = self::getBaseTopNQuery( $partnerId, $filter, array(self::EVENT_TYPE_PLAY), self::DIMENSION_URL, - self::OUTPUT_PLAYS); + self::OUTPUT_PLAYS, + self::getLimit($limit)); $query[self::DRUID_AGGR] = array( self::getPlayCountAggregator(), ); @@ -379,7 +390,7 @@ public static function entrySyndicationTotal($partnerId, $filter) return $result; } - public static function entryTimeline($partnerId, $filter) + public static function entryTimeline($partnerId, $filter, $limit) { $query = self::getBaseTimeseriesQuery( $partnerId, @@ -407,12 +418,8 @@ public static function entryTimeline($partnerId, $filter) return $result; } - public static function entryGeoTimeline($partnerId, $filter) + public static function entryGeoTimeline($partnerId, $filter, $limit) { - // Note: while the report is called 'time line' we use granularity all since - // all requests have fromTime = toTime, and grouping by 'time' seems like - // too much information to present. - $dimensions = array( self::DIMENSION_ENTRY_ID => self::OUTPUT_ENTRY_ID, self::DIMENSION_LOCATION_CITY => self::OUTPUT_CITY_NAME, @@ -439,7 +446,7 @@ public static function entryGeoTimeline($partnerId, $filter) } $query[self::DRUID_LIMIT_SPEC] = self::getDefaultLimitSpec( - self::MAX_RESULTS, + self::getLimit($limit), array(self::getOrderByColumnSpec( $orderByField, self::DRUID_DESCENDING, @@ -448,8 +455,7 @@ public static function entryGeoTimeline($partnerId, $filter) self::addBaseAggregations($query); - $query[self::DRUID_GRANULARITY] = self::getGranularityAll(); - $queryResult = self::runQuery($query); + $queryResult = self::runGranularityPeriodQuery($query, self::VIEW_EVENT_PERIOD); KalturaLog::log("Druid returned [" . count($queryResult) . "] rows"); // format the results diff --git a/alpha/apps/kaltura/lib/storage/kFileSyncUtils.class.php b/alpha/apps/kaltura/lib/storage/kFileSyncUtils.class.php index 7dc3c3b2898..e14a3cba215 100644 --- a/alpha/apps/kaltura/lib/storage/kFileSyncUtils.class.php +++ b/alpha/apps/kaltura/lib/storage/kFileSyncUtils.class.php @@ -1116,7 +1116,7 @@ public static function createSyncFileForKey ( $rootPath, $filePath, FileSyncKey /** * @param FileSyncKey $key * @param StorageProfile $externalStorage - * @return SyncFile + * @return FileSync */ public static function createPendingExternalSyncFileForKey(FileSyncKey $key, StorageProfile $externalStorage, $isDir = false) { diff --git a/alpha/apps/kaltura/lib/storage/kStorageExporter.php b/alpha/apps/kaltura/lib/storage/kStorageExporter.php index b94d557c2b8..8f5af6158c2 100644 --- a/alpha/apps/kaltura/lib/storage/kStorageExporter.php +++ b/alpha/apps/kaltura/lib/storage/kStorageExporter.php @@ -124,9 +124,8 @@ static protected function export(entry $entry, StorageProfile $externalStorage, $externalFileSync = kFileSyncUtils::createPendingExternalSyncFileForKey($key, $externalStorage, $fileSync->getIsDir()); - $parent_file_sync = kFileSyncUtils::resolve($fileSync); - $srcFileSyncPath = $parent_file_sync->getFileRoot() . $parent_file_sync->getFilePath(); - kJobsManager::addStorageExportJob(null, $entry->getId(), $entry->getPartnerId(), $externalStorage, $externalFileSync, $srcFileSyncPath, $force, $fileSync->getDc()); + $srcFileSync = kFileSyncUtils::resolve($fileSync); + kJobsManager::addStorageExportJob(null, $entry->getId(), $entry->getPartnerId(), $externalStorage, $externalFileSync, $srcFileSync, $force, $fileSync->getDc()); return true; } diff --git a/alpha/apps/kaltura/lib/webservices/kSessionUtils.class.php b/alpha/apps/kaltura/lib/webservices/kSessionUtils.class.php index 47c7e61a2e8..c4ee6845438 100644 --- a/alpha/apps/kaltura/lib/webservices/kSessionUtils.class.php +++ b/alpha/apps/kaltura/lib/webservices/kSessionUtils.class.php @@ -557,24 +557,21 @@ public function getEnableCategoryModeration() public function getDisableEntitlementForEntry() { - // break all privileges to their pairs - this is to support same "multi-priv" method expected for - // edit privilege (edit:XX,edit:YYY,...) - $allPrivileges = explode(',', $this->privileges); - $entries = array(); - // foreach pair - check privileges on playlist - foreach($allPrivileges as $priv) + // foreach privileges group + foreach( $this->parsedPrivileges as $privilegeType => $privileges) { - $exPrivileges = explode(':', $priv); - if ($exPrivileges[0] == self::PRIVILEGE_DISABLE_ENTITLEMENT_FOR_ENTRY) + if ($privilegeType == self::PRIVILEGE_DISABLE_ENTITLEMENT_FOR_ENTRY) { - $entries[] = $exPrivileges[1]; - - $entry = entryPeer::retrieveByPKNoFilter($exPrivileges[1], null, false); - if($entry && $entry->getParentEntryId()) + foreach($privileges as $privilege) { - $entries[] = $entry->getParentEntryId(); + $entries[] = $privilege; + $entry = entryPeer::retrieveByPKNoFilter($privilege, null, false); + if ($entry && $entry->getParentEntryId()) + { + $entries[] = $entry->getParentEntryId(); + } } } } diff --git a/alpha/apps/kaltura/modules/extwidget/actions/embedPlaykitJsAction.class.php b/alpha/apps/kaltura/modules/extwidget/actions/embedPlaykitJsAction.class.php index 6f3299b8e5b..7e72a5e3532 100644 --- a/alpha/apps/kaltura/modules/extwidget/actions/embedPlaykitJsAction.class.php +++ b/alpha/apps/kaltura/modules/extwidget/actions/embedPlaykitJsAction.class.php @@ -8,12 +8,13 @@ class embedPlaykitJsAction extends sfAction { const UI_CONF_ID_PARAM_NAME = "uiconf_id"; const PARTNER_ID_PARAM_NAME = "partner_id"; + const VERSIONS_PARAM_NAME = "versions"; const ENTRY_ID_PARAM_NAME = "entry_id"; const CONFIG_PARAM_NAME = "config"; const REGENERATE_PARAM_NAME = "regenerate"; const IFRAME_EMBED_PARAM_NAME = "iframeembed"; const AUTO_EMBED_PARAM_NAME = "autoembed"; - + private $bundleCache = null; private $sourceMapsCache = null; private $eTagHash = null; @@ -102,9 +103,7 @@ public static function buildBundleLocked($context) private function formatBundleContent($bundleContent) { $bundleContentParts = explode(",", $bundleContent, 2); - $bundleContent = $this->appendUiConfToContent($bundleContentParts[1]); - $bundleContent = $this->appendEnvConfigToContent($bundleContent); - + $bundleContent = $this->appendConfig($bundleContentParts[1]); $autoEmbed = $this->getRequestParameter(self::AUTO_EMBED_PARAM_NAME); $iframeEmbed = $this->getRequestParameter(self::IFRAME_EMBED_PARAM_NAME); @@ -126,29 +125,25 @@ private function formatBundleContent($bundleContent) return $bundleContent; } - private function appendUiConfToContent($content) + private function appendConfig($content) { - $config = array(); - $config["config"] = $this->playerConfig; - $config = json_encode($config); - - if ($config === false) - { - KExternalErrors::dieError(KExternalErrors::INVALID_PARAMETER, "Invalid config object"); - } - - $kalturaPlayerConfig = " - (function(){(KalturaPlayer.UiConf = KalturaPlayer.UiConf || {}) [\"" . $this->uiconfId . "\"] = $config; - })();"; - - $content .= $kalturaPlayerConfig; - - return $content; + $uiConf = $this->playerConfig; + $uiConf["env"] = $this->getEnvConfig(); + $uiConfJson = json_encode($uiConf); + if ($uiConfJson === false) + { + KExternalErrors::dieError(KExternalErrors::INVALID_PARAMETER, "Invalid config object"); + } + $confNS = "window.__kalturaplayerdata"; + $content .= " + $confNS = ($confNS || {}); + $confNS.UIConf = ($confNS.UIConf||{});$confNS.UIConf[\"" . $this->uiconfId . "\"]=$uiConfJson; + "; + return $content; } - private function appendEnvConfigToContent($content) + private function getEnvConfig() { - $protocol = infraRequestUtils::getProtocol(); // The default Kaltura service url: @@ -156,34 +151,23 @@ private function appendEnvConfigToContent($content) // Default Kaltura CDN url: $cdnUrl = requestUtils::getCdnHost($protocol); // Default Stats URL - $statsServiceUrl = ($protocol == "https") ? $this->buildUrl($protocol,"stats_host_https") : $this->buildUrl($protocol,"stats_host"); + $statsServiceUrl = $this->buildUrl($protocol,"stats_host"); // Default Live Stats URL - $liveStatsServiceUrl = ($protocol == "https") ? $this->buildUrl($protocol,"live_stats_host_https") : $this->buildUrl($protocol,"live_stats_host"); + $liveStatsServiceUrl = $this->buildUrl($protocol,"live_stats_host"); // Default Kaltura Analytics URL - $analyticsServiceUrl = ($protocol == "https") ? $this->buildUrl($protocol,"analytics_host_https") : $this->buildUrl($protocol,"analytics_host"); + $analyticsServiceUrl = $this->buildUrl($protocol,"analytics_host"); // Get Kaltura Supported API Features $apiFeatures = $this->getFromConfig('features'); $envConfig = array( - "ServiceUrl" => $serviceUrl, - "CDNUrl" => $cdnUrl, - "StatsServiceUrl" => $statsServiceUrl, - "LiveStatsServiceUrl" => $liveStatsServiceUrl, - "AnalyticsServiceUrl" => $analyticsServiceUrl, - "ApiFeatures" => $apiFeatures + "serviceUrl" => $serviceUrl, + "cdnUrl" => $cdnUrl, + "statsServiceUrl" => $statsServiceUrl, + "liveStatsServiceUrl" => $liveStatsServiceUrl, + "analyticsServiceUrl" => $analyticsServiceUrl, + "apiFeatures" => $apiFeatures ); - - $envConfig = json_encode($envConfig); - - if ($envConfig !== false) - { - $kalturaPlayerEnvConfig = " - (function(){KalturaPlayer.EnvConfig = $envConfig; - })();"; - return $content . $kalturaPlayerEnvConfig; - } - - return $content; + return $envConfig; } private function getFromConfig($key) @@ -196,6 +180,10 @@ private function getFromConfig($key) private function buildUrl($protocol, $key) { + if ($protocol == "https") + { + $key .= "_https"; + } $configValue = $this->getFromConfig($key); $port = (($_SERVER['SERVER_PORT']) != '80' && $_SERVER['SERVER_PORT'] != '443')?':'.$_SERVER['SERVER_PORT']:''; if( $key && $configValue) @@ -320,30 +308,60 @@ private function getIfarmEmbedCode($bundleContent) '; return $htmlDoc; } + + private function toAssociativeArray($input) + { + $configs = explode(",", $input); + $arr = array(); + foreach($configs as $conf) + { + $obj = explode("=", $conf); + $key = $obj[0]; + $value = $obj[1]; + $arr[$key] = $value; + } + return $arr; + } + + private function mergeVersionsParamIntoConfig() + { + //Get version from QS + $versions = $this->getRequestParameter(self::VERSIONS_PARAM_NAME); + if ($versions) { + $pattern = '/[^?&,]+=[^?&,]+(?>,[^,?&]+=[^,?&]+)*/'; // key value object + $success = preg_match($pattern, $versions, $matches); + if ($success && strlen($matches[0]) === strlen($versions)) { // the whole versions string matches the pattern + $versionsArr = $this->toAssociativeArray($versions); + $this->bundleConfig = array_merge($this->bundleConfig, $versionsArr); + } + } + } - private function setLatestOrBetaVersionNumber($confVars) + private function setLatestOrBetaVersionNumber() { - //if latest/beta version required set version number in config obj - $isLatestVersionRequired = strpos($confVars, "{latest}") !== false; - $isBetaVersionRequired = strpos($confVars, "{beta}") !== false; - - if ($isLatestVersionRequired || $isBetaVersionRequired) { - $latestVersionsMapPath = $this->sourcesPath . "/latest.json"; - $latestVersionMap = file_exists($latestVersionsMapPath) ? json_decode(file_get_contents($latestVersionsMapPath), true) : null; - - $betaVersionsMapPath = $this->sourcesPath . "/beta.json"; - $betatVersionMap = file_exists($betaVersionsMapPath) ? json_decode(file_get_contents($betaVersionsMapPath), true) : null; - - foreach ($this->bundleConfig as $key => $val) - { - if ($val == "{latest}" && $latestVersionMap != null) - { - $this->bundleConfig[$key] = $latestVersionMap[$key]; - } - - if ($val == "{beta}" && $betatVersionMap != null) + if ($this->bundleConfig) { + //if latest/beta version required set version number in config obj + $isLatestVersionRequired = array_search("{latest}", $this->bundleConfig) !== false; + $isBetaVersionRequired = array_search("{beta}", $this->bundleConfig) !== false; + + if ($isLatestVersionRequired || $isBetaVersionRequired) { + $latestVersionsMapPath = $this->sourcesPath . "/latest.json"; + $latestVersionMap = file_exists($latestVersionsMapPath) ? json_decode(file_get_contents($latestVersionsMapPath), true) : null; + + $betaVersionsMapPath = $this->sourcesPath . "/beta.json"; + $betaVersionMap = file_exists($betaVersionsMapPath) ? json_decode(file_get_contents($betaVersionsMapPath), true) : null; + + foreach ($this->bundleConfig as $key => $val) { - $this->bundleConfig[$key] = $betatVersionMap[$key]; + if ($val == "{latest}" && $latestVersionMap != null) + { + $this->bundleConfig[$key] = $latestVersionMap[$key]; + } + + if ($val == "{beta}" && $betaVersionMap != null) + { + $this->bundleConfig[$key] = $betaVersionMap[$key]; + } } } } @@ -409,7 +427,8 @@ private function initMembers() } $this->bundleConfig = json_decode($confVars, true); - $this->setLatestOrBetaVersionNumber($confVars); + $this->mergeVersionsParamIntoConfig(); + $this->setLatestOrBetaVersionNumber(); $this->setBundleName(); } diff --git a/alpha/apps/kaltura/modules/extwidget/actions/playManifestAction.class.php b/alpha/apps/kaltura/modules/extwidget/actions/playManifestAction.class.php index 9023e55c96b..da0501c7001 100644 --- a/alpha/apps/kaltura/modules/extwidget/actions/playManifestAction.class.php +++ b/alpha/apps/kaltura/modules/extwidget/actions/playManifestAction.class.php @@ -752,8 +752,13 @@ private function shouldIncludeStorageProfile($storageProfile) if($this->requestedDeliveryProfileIds) { $deliveryIdsByStreamerType = $storageProfile->getDeliveryProfileIds(); - $storageStreamerTypeDeliveryProfileIds = $deliveryIdsByStreamerType[$this->deliveryAttributes->getFormat()]; - return isset($storageStreamerTypeDeliveryProfileIds) && count(array_intersect($this->requestedDeliveryProfileIds, $storageStreamerTypeDeliveryProfileIds)); + if(isset( $deliveryIdsByStreamerType[$this->deliveryAttributes->getFormat()])) + { + $storageStreamerTypeDeliveryProfileIds = $deliveryIdsByStreamerType[$this->deliveryAttributes->getFormat()]; + return count(array_intersect($this->requestedDeliveryProfileIds, $storageStreamerTypeDeliveryProfileIds)); + } + + return false; } return true; diff --git a/alpha/apps/kaltura/modules/kmc/actions/kmc4Action.class.php b/alpha/apps/kaltura/modules/kmc/actions/kmc4Action.class.php index d9075f02da2..9f8db66fdc3 100644 --- a/alpha/apps/kaltura/modules/kmc/actions/kmc4Action.class.php +++ b/alpha/apps/kaltura/modules/kmc/actions/kmc4Action.class.php @@ -6,6 +6,8 @@ class kmc4Action extends kalturaAction { const CURRENT_KMC_VERSION = 4; + const HTML5_STUDIO_TAG = 'HTML5Studio'; + const STUDIO_V3_TAG = 'HTML5StudioV3'; const LIVE_ANALYTICS_UICONF_TAG = 'livea_player'; const LIVE_DASHBOARD_UICONF_TAG = 'lived_player'; @@ -76,6 +78,7 @@ public function execute ( ) $useEmbedCodeProtocolHttps = PermissionPeer::isValidForPartner(PermissionName::FEATURE_EMBED_CODE_DEFAULT_PROTOCOL_HTTPS, $this->partner_id); $showFlashStudio = PermissionPeer::isValidForPartner(PermissionName::FEATURE_SHOW_FLASH_STUDIO, $this->partner_id); $showHTMLStudio = PermissionPeer::isValidForPartner(PermissionName::FEATURE_SHOW_HTML_STUDIO, $this->partner_id); + $showStudioV3 = PermissionPeer::isValidForPartner(PermissionName::FEATURE_V3_STUDIO_PERMISSION, $this->partner_id); $deliveryTypes = $partner->getDeliveryTypes(); $embedCodeTypes = $partner->getEmbedCodeTypes(); $defaultDeliveryType = ($partner->getDefaultDeliveryType()) ? $partner->getDefaultDeliveryType() : 'http'; @@ -155,15 +158,19 @@ public function execute ( ) $this->content_uiconds_clipapp_kdp = kmcUtils::find_confs_by_usage_tag($kmcGeneralTemplateUiConf, "kmc_kdpClipApp", false, $kmcGeneralUiConf); $this->content_uiconds_clipapp_kclip = kmcUtils::find_confs_by_usage_tag($kmcGeneralTemplateUiConf, "kmc_kClipClipApp", false, $kmcGeneralUiConf); - $this->studioUiConf = kmcUtils::getStudioUiconf(kConf::get("studio_version")); + $this->studioUiConf = kmcUtils::getUiconfByTagAndVersion(self::HTML5_STUDIO_TAG, kConf::get("studio_version")); $this->content_uiconfs_studio_v2 = isset($this->studioUiConf) ? array_values($this->studioUiConf) : null; $this->content_uiconf_studio_v2 = (is_array($this->content_uiconfs_studio_v2) && reset($this->content_uiconfs_studio_v2)) ? reset($this->content_uiconfs_studio_v2) : null; - - $this->liveAUiConf = kmcUtils::getLiveUiconfByTag(self::LIVE_ANALYTICS_UICONF_TAG); + + $this->studioV3UiConf = kmcUtils::getUiconfByTagAndVersion(self::STUDIO_V3_TAG, kConf::get("studio_v3_version")); + $this->content_uiconfs_studio_v3 = isset($this->studioV3UiConf) ? array_values($this->studioV3UiConf) : null; + $this->content_uiconf_studio_v3 = (is_array($this->content_uiconfs_studio_v3) && reset($this->content_uiconfs_studio_v3)) ? reset($this->content_uiconfs_studio_v3) : null; + + $this->liveAUiConf = kmcUtils::getUiconfByTagAndVersion(self::LIVE_ANALYTICS_UICONF_TAG, kConf::get("liveanalytics_version")); $this->content_uiconfs_livea = isset($this->liveAUiConf) ? array_values($this->liveAUiConf) : null; $this->content_uiconf_livea = (is_array($this->content_uiconfs_livea) && reset($this->content_uiconfs_livea)) ? reset($this->content_uiconfs_livea) : null; - $this->liveDUiConf = kmcUtils::getLiveUiconfByTag(self::LIVE_DASHBOARD_UICONF_TAG); + $this->liveDUiConf = kmcUtils::getUiconfByTagAndVersion(self::LIVE_DASHBOARD_UICONF_TAG, kConf::get("live_dashboard_version")); $this->content_uiconfs_lived = isset($this->liveDUiConf) ? array_values($this->liveDUiConf) : null; $this->content_uiconf_lived = (is_array($this->content_uiconfs_lived) && reset($this->content_uiconfs_lived)) ? reset($this->content_uiconfs_lived) : null; @@ -213,6 +220,17 @@ public function execute ( ) 'config' => isset($this->content_uiconf_studio_v2) ? $this->content_uiconf_studio_v2->getConfig() : '', 'showFlashStudio' => $showFlashStudio, 'showHTMLStudio' => $showHTMLStudio, + 'showStudioV3' => $showStudioV3, + 'html5_version' => kConf::get("html5_version") + ), + 'studioV3' => array( + 'version' => kConf::get("studio_v3_version"), + 'uiConfID' => isset($this->content_uiconf_studio_v3) ? $this->content_uiconf_studio_v3->getId() : '', + 'config' => isset($this->content_uiconf_studio_v3) ? $this->content_uiconf_studio_v3->getConfig() : '', + 'showFlashStudio' => $showFlashStudio, + 'showHTMLStudio' => $showHTMLStudio, + 'showStudioV3' => $showStudioV3, + 'html5_version' => kConf::get("html5_version") ), 'liveanalytics' => array( 'version' => kConf::get("liveanalytics_version"), diff --git a/alpha/apps/kaltura/modules/kmc/lib/kmcUtils.class.php b/alpha/apps/kaltura/modules/kmc/lib/kmcUtils.class.php index e33905101e0..80c509affd6 100644 --- a/alpha/apps/kaltura/modules/kmc/lib/kmcUtils.class.php +++ b/alpha/apps/kaltura/modules/kmc/lib/kmcUtils.class.php @@ -114,30 +114,18 @@ public static function getPartnersUiconfs($partner_id, $tag) return $confs; } - public static function getLiveUiconfByTag($uiConfTag) - { - $c = new Criteria(); - $c->addAnd(uiConfPeer::PARTNER_ID, 0); - $c->addAnd ( uiConfPeer::STATUS , uiConf::UI_CONF_STATUS_READY ); - $c->addAnd ( uiConfPeer::TAGS, '%'.$uiConfTag.'%', Criteria::LIKE ); - $c->addAnd ( uiConfPeer::TAGS, '%deprecated%', Criteria::NOT_LIKE ); - $c->addDescendingOrderByColumn(uiConfPeer::CREATED_AT); - $confs = uiConfPeer::doSelect($c); - return $confs; - } - - public static function getStudioUiconf($version) - { - $c = new Criteria(); - $tag = 'HTML5Studio_' . $version; - $c->addAnd(uiConfPeer::PARTNER_ID, 0); - $c->addAnd ( uiConfPeer::STATUS , uiConf::UI_CONF_STATUS_READY ); - $c->addAnd ( uiConfPeer::TAGS, '%'.$tag.'%', Criteria::LIKE ); - $c->addAnd ( uiConfPeer::TAGS, '%deprecated%', Criteria::NOT_LIKE ); - $c->addDescendingOrderByColumn(uiConfPeer::CREATED_AT); - $confs = uiConfPeer::doSelect($c); - return $confs; - } + public static function getUiconfByTagAndVersion($uiConfTag, $version) { + $c = new Criteria(); + $c->addAnd(uiConfPeer::PARTNER_ID, 0); + $c->addAnd ( uiConfPeer::STATUS , uiConf::UI_CONF_STATUS_READY ); + $c->addAnd ( uiConfPeer::TAGS, '%' . $uiConfTag . '%', Criteria::LIKE ); + $c->addAnd ( uiConfPeer::TAGS, '%' . $version . '%', Criteria::LIKE ); + $c->addAnd ( uiConfPeer::TAGS, '%deprecated%', Criteria::NOT_LIKE ); + $c->addDescendingOrderByColumn(uiConfPeer::CREATED_AT); + $confs = uiConfPeer::doSelect($c); + return $confs; + } + public static function getAllKMCUiconfs($module_tag, $module_version, $template_partner_id) { $c = new Criteria(); diff --git a/alpha/lib/model/DeliveryProfileLive.php b/alpha/lib/model/DeliveryProfileLive.php index 5fa5c316d45..370a3fa01c6 100644 --- a/alpha/lib/model/DeliveryProfileLive.php +++ b/alpha/lib/model/DeliveryProfileLive.php @@ -1,7 +1,9 @@ getDynamicAttributes()->getEntry(); + if ($entry->getExplicitLive()) + { + $userType = self::USER_TYPE_ADMIN; + if (!$entry->canViewExplicitLive()) + $userType = self::USER_TYPE_USER; + $livePackagerUrl .= "type/$userType/"; + } $secureToken = $this->generateLiveSecuredPackagerToken($livePackagerUrl); - $livePackagerUrl .= "t/$secureToken/"; - + $livePackagerUrl .= "t/$secureToken/"; + KalturaLog::debug("Live Packager base stream Url [$livePackagerUrl]"); return $livePackagerUrl; } diff --git a/alpha/lib/model/DeliveryProfilePeer.php b/alpha/lib/model/DeliveryProfilePeer.php index 1878e1e30df..215fc58ca54 100644 --- a/alpha/lib/model/DeliveryProfilePeer.php +++ b/alpha/lib/model/DeliveryProfilePeer.php @@ -346,10 +346,11 @@ protected static function getDeliveryByIds($deliveryIds, Partner $partner, $stre if(isset( $partnersDeliveryProfileIdsByUserOrder[$deliveryAttributes->getFormat()])) { $partnersDeliveryProfileIdsByUserOrder = $partnersDeliveryProfileIdsByUserOrder[$deliveryAttributes->getFormat()]; - array_walk($deliveries, "DeliveryProfileComparator::decorateWithUserOrder", $partnersDeliveryProfileIdsByUserOrder); - uasort($deliveries, array($cmp, "compare")); } + array_walk($deliveries, "DeliveryProfileComparator::decorateWithUserOrder", $partnersDeliveryProfileIdsByUserOrder); + uasort($deliveries, array($cmp, "compare")); + return $deliveries; } diff --git a/alpha/lib/model/DeliveryProfileVod.php b/alpha/lib/model/DeliveryProfileVod.php index 7340f229de7..46cb401a6a9 100644 --- a/alpha/lib/model/DeliveryProfileVod.php +++ b/alpha/lib/model/DeliveryProfileVod.php @@ -52,7 +52,7 @@ protected function getBaseUrl(asset $flavorAsset) { $url .= $this->getDynamicAttributes()->getUsePlayServer() ? $this->getPlayServerUrl() : ''; $url .= $this->getDynamicAttributes()->getHasValidSequence() ? '/sequence/'.$this->getDynamicAttributes()->getSequence() : ''; - if ($entry->getType() == entryType::PLAYLIST || $this->getDynamicAttributes()->getHasValidSequence() && $flavorAsset->getType() == assetType::FLAVOR) + if ($entry->getType() == entryType::PLAYLIST || ($this->getDynamicAttributes()->getHasValidSequence() && $flavorAsset->getType() == assetType::FLAVOR)) { $partner = $entry->getPartner(); $entryVersion = $entry->getVersion(); diff --git a/alpha/lib/model/LiveEntry.php b/alpha/lib/model/LiveEntry.php index 9e473d87391..f62274d5321 100644 --- a/alpha/lib/model/LiveEntry.php +++ b/alpha/lib/model/LiveEntry.php @@ -299,7 +299,7 @@ public function getLastCuePointSyncTime ( ) { return (int) $this->getFromCustom public function getPushPublishEnabled() { - return $this->getFromCustomData("push_publish_enabled", null, false); + return $this->getFromCustomData("push_publish_enabled"); } public function setPushPublishEnabled($v) @@ -448,7 +448,18 @@ protected function getMediaServersHostnames() KalturaLog::info("media servers hostnames: " . print_r($hostnames,true)); return $hostnames; } - + + public function canViewExplicitLive() + { + $isAdmin = kCurrentContext::$ks_object && kCurrentContext::$ks_object->isAdmin(); + $userIsOwner = kCurrentContext::getCurrentKsKuserId() == $this->getKuserId(); + $isUserAllowedPreview = $this->isEntitledKuserEdit(kCurrentContext::getCurrentKsKuserId()); + $isMediaServerPartner = (kCurrentContext::$ks_partner_id == Partner::MEDIA_SERVER_PARTNER_ID); + if (!$isAdmin && !$userIsOwner && !$isUserAllowedPreview && !$isMediaServerPartner) + return false; + return true; + } + /** * @return boolean */ @@ -456,10 +467,7 @@ public function isCurrentlyLive($currentDcOnly = false) { if ($this->getViewMode() == ViewMode::PREVIEW) { - $isAdmin = kCurrentContext::$ks_object && kCurrentContext::$ks_object->isAdmin(); - $userIsOwner = kCurrentContext::getCurrentKsKuserId() == $this->getKuserId(); - $isUserAllowedPreview = $this->isEntitledKuserEdit(kCurrentContext::getCurrentKsKuserId()); - if (!$isAdmin && !$userIsOwner && !$isUserAllowedPreview) + if (!$this->canViewExplicitLive()) return false; } diff --git a/alpha/lib/model/Partner.php b/alpha/lib/model/Partner.php index 7f95652720d..6c9bba218ff 100644 --- a/alpha/lib/model/Partner.php +++ b/alpha/lib/model/Partner.php @@ -64,6 +64,8 @@ class Partner extends BasePartner const HTML_PURIFIER_BASE_LIST_USAGE = "htmlPurifierBaseListUsage"; + private $partnerUsagePercent; + public function save(PropelPDO $con = null) { PartnerPeer::removePartnerFromCache( $this->getId() ); @@ -1011,7 +1013,12 @@ public function setBroadcastUrlManager($v) {$this->putInCustomData('broadcast_ public function setPrimaryBroadcastUrl($v) {$this->putInCustomData('primary_broadcast_url', $v);} public function setSecondaryBroadcastUrl($v) {$this->putInCustomData('secondary_broadcast_url', $v);} public function setLiveStreamPlaybackUrlConfigurations($v) {$this->putInCustomData('live_stream_playback_url_configurations', $v);} - + public function setLastFreeTrialNotificationDay($v) {$this->putInCustomData('last_free_trial_notification_day', $v);} + public function setTemplateEntriesNum($v) {$this->putInCustomData('template_entries_num', $v);} + public function setTemplateCategoriesNum($v) {$this->putInCustomData('template_categories_num', $v);} + public function setTemplateCustomMetadataNum($v) {$this->putInCustomData('template_custom_metadata_num', $v);} + public function setEntriesChangedByPartnerNum($v) {$this->putInCustomData('entries_changed_by_partner_num', $v);} + public function getLoginUsersQuota() {return $this->getFromCustomData('login_users_quota', null, 0);} public function getAdminLoginUsersQuota() {return $this->getFromCustomData('admin_login_users_quota', null, 3);} public function getPublishersQuota() {return $this->getFromCustomData('publishers_quota', null, 0);} @@ -1055,6 +1062,11 @@ public function getBroadcastUrlManager() {return $this->getFromCustomData('bro public function getPrimaryBroadcastUrl() {return $this->getFromCustomData('primary_broadcast_url');} public function getSecondaryBroadcastUrl() {return $this->getFromCustomData('secondary_broadcast_url');} public function getLiveStreamPlaybackUrlConfigurations() {return $this->getFromCustomData('live_stream_playback_url_configurations', null, array());} + public function getLastFreeTrialNotificationDay() {return $this->getFromCustomData('last_free_trial_notification_day');} + public function getTemplateEntriesNum() {return $this->getFromCustomData('template_entries_num', null, 0);} + public function getTemplateCategoriesNum() {return $this->getFromCustomData('template_categories_num', null, 0);} + public function getTemplateCustomMetadataNum() {return $this->getFromCustomData('template_custom_metadata_num', null, 0);} + public function getEntriesChangedByPartnerNum() {return $this->getFromCustomData('entries_changed_by_partner_num', null, 0);} public function setLiveStreamBroadcastUrlConfigurations($key, $value) @@ -1827,4 +1839,32 @@ public function setDefaultLiveStreamSegmentDuration($v) { $this->putInCustomData( "default_live_stream_segment_duration", $v ); } + + /** + * @param string $name + * @param string $namespace + * @return boolean True if $name has been modified. + */ + public function isCustomDataModified($name = null, $namespace = '') + { + if(isset($this->oldCustomDataValues[$namespace]) && (is_null($name) || array_key_exists($name, $this->oldCustomDataValues[$namespace]))) + { + return true; + } + + return false; + } + + + public function getPartnerUsagePercent() + { + if (!$this->partnerUsagePercent) + return 0; + return $this->partnerUsagePercent ; + } + + public function setPartnerUsagePercent($v) + { + $this->partnerUsagePercent = $v; + } } diff --git a/alpha/scripts/utils/exportToNetStorage.php b/alpha/scripts/utils/exportToNetStorage.php index 4b5f624251b..8cff554fcc7 100644 --- a/alpha/scripts/utils/exportToNetStorage.php +++ b/alpha/scripts/utils/exportToNetStorage.php @@ -116,11 +116,10 @@ { $fileSync = kFileSyncUtils::createPendingExternalSyncFileForKey($key, $storageProfile); - $dcFileSync = kFileSyncUtils::getReadyInternalFileSyncForKey($key); + $srcFileSync = kFileSyncUtils::getReadyInternalFileSyncForKey($key); - /* @var $dcFileSync FileSync */ - $srcFileSyncLocalPath = $dcFileSync->getFileRoot() . $dcFileSync->getFilePath(); - kJobsManager::addStorageExportJob(null, $entry->getId(), $partnerId, $storageProfile, $fileSync, $srcFileSyncLocalPath, true, $dcFileSync->getDc()); + /* @var $srcFileSync FileSync */ + kJobsManager::addStorageExportJob(null, $entry->getId(), $partnerId, $storageProfile, $fileSync, $srcFileSync, true, $srcFileSync->getDc()); } echo $entry->getId() . " - " . count($keys) . " keys exported\n\n"; diff --git a/alpha/scripts/utils/updatePuserOnCategoryKuser.php b/alpha/scripts/utils/updatePuserOnCategoryKuser.php new file mode 100644 index 00000000000..01153410ce2 --- /dev/null +++ b/alpha/scripts/utils/updatePuserOnCategoryKuser.php @@ -0,0 +1,52 @@ +"."\n"); + +$partnerId = $argv[1] ; +$kusersPath = $argv[2]; +$dryrun = true; +if($argc == 4 && $argv[3] == 'realrun') + $dryrun = false; +KalturaStatement::setDryRun($dryrun); +KalturaLog::debug('dryrun value: ['.$dryrun.']'); +$kusers = file ($kusersPath) or die ('Could not read file'."\n"); + +foreach ($kusers as $kuserId) +{ + $kuserId = trim($kuserId); + $puserIdFromKuserTable = getPuserIdFromKuserTable ($partnerId, $kuserId); + if($puserIdFromKuserTable) + { + $categoryList = getCategoryListByKuser($partnerId, $kuserId); + foreach ($categoryList as $categoryKuserItem) + { + $puserIdFromCategoryKuser = $categoryKuserItem->getPuserId(); + if (strcmp(trim($puserIdFromKuserTable),trim($puserIdFromCategoryKuser))) + { + KalturaLog::debug('kuserId ['.$kuserId.'] : update puser_id on categoryKuser table from ['.$puserIdFromCategoryKuser.'] to ['.$puserIdFromKuserTable.']'); + kCurrentContext::$partner_id = $partnerId; + $categoryKuserItem->setPuserId($puserIdFromKuserTable); + $categoryKuserItem->save(); + } + } + } +} + +function getPuserIdFromKuserTable($partnerId, $kuserId) +{ + $Critiria = new Criteria(); + $Critiria->add(kuserPeer::PARTNER_ID, $partnerId); + $Critiria->add(kuserPeer::ID, $kuserId); + $kuser = kuserPeer::doSelectOne($Critiria); + return $kuser->getPuserId(); +} + +function getCategoryListByKuser($partnerId, $kuserId) +{ + $Critiria = new Criteria(); + $Critiria->add(categoryKuserPeer::PARTNER_ID, $partnerId); + $Critiria->add(categoryKuserPeer::KUSER_ID, $kuserId); + return categoryKuserPeer::doSelect($Critiria); +} diff --git a/alpha/web/lib/js/kmc/6.0.11/kmc.js b/alpha/web/lib/js/kmc/6.0.11/kmc.js index 73352ff2135..fe686eac75f 100644 --- a/alpha/web/lib/js/kmc/6.0.11/kmc.js +++ b/alpha/web/lib/js/kmc/6.0.11/kmc.js @@ -1,1408 +1,1408 @@ -/*! KMC - v6.0.11 - 2017-09-27 -* https://github.com/kaltura/KMC_V2 -* Copyright (c) 2017 Amir Chervinsky; Licensed GNU */ -/** - * angular-translate - v1.1.1 - 2013-11-24 - * http://github.com/PascalPrecht/angular-translate - * Copyright (c) 2013 ; Licensed - */ -angular.module('pascalprecht.translate', ['ng']).run([ - '$translate', - function ($translate) { - var key = $translate.storageKey(), storage = $translate.storage(); - if (storage) { - if (!storage.get(key)) { - if (angular.isString($translate.preferredLanguage())) { - $translate.uses($translate.preferredLanguage()); - } else { - storage.set(key, $translate.uses()); - } - } else { - $translate.uses(storage.get(key)); - } - } else if (angular.isString($translate.preferredLanguage())) { - $translate.uses($translate.preferredLanguage()); - } - } -]); -angular.module('pascalprecht.translate').provider('$translate', [ - '$STORAGE_KEY', - function ($STORAGE_KEY) { - var $translationTable = {}, $preferredLanguage, $fallbackLanguage, $uses, $nextLang, $storageFactory, $storageKey = $STORAGE_KEY, $storagePrefix, $missingTranslationHandlerFactory, $interpolationFactory, $interpolatorFactories = [], $loaderFactory, $loaderOptions, $notFoundIndicatorLeft, $notFoundIndicatorRight, NESTED_OBJECT_DELIMITER = '.'; - var translations = function (langKey, translationTable) { - if (!langKey && !translationTable) { - return $translationTable; - } - if (langKey && !translationTable) { - if (angular.isString(langKey)) { - return $translationTable[langKey]; - } else { - angular.extend($translationTable, flatObject(langKey)); - } - } else { - if (!angular.isObject($translationTable[langKey])) { - $translationTable[langKey] = {}; - } - angular.extend($translationTable[langKey], flatObject(translationTable)); - } - return this; - }; - var flatObject = function (data, path, result, prevKey) { - var key, keyWithPath, val; - if (!path) { - path = []; - } - if (!result) { - result = {}; - } - for (key in data) { - if (!data.hasOwnProperty(key)) - continue; - val = data[key]; - if (angular.isObject(val)) { - flatObject(val, path.concat(key), result, key); - } else { - keyWithPath = path.length ? '' + path.join(NESTED_OBJECT_DELIMITER) + NESTED_OBJECT_DELIMITER + key : key; - if (path.length && key === prevKey) { - keyWithShortPath = '' + path.join(NESTED_OBJECT_DELIMITER); - result[keyWithShortPath] = '@:' + keyWithPath; - } - result[keyWithPath] = val; - } - } - return result; - }; - this.translations = translations; - this.addInterpolation = function (factory) { - $interpolatorFactories.push(factory); - return this; - }; - this.useMessageFormatInterpolation = function () { - return this.useInterpolation('$translateMessageFormatInterpolation'); - }; - this.useInterpolation = function (factory) { - $interpolationFactory = factory; - return this; - }; - this.preferredLanguage = function (langKey) { - if (langKey) { - $preferredLanguage = langKey; - return this; - } else { - return $preferredLanguage; - } - }; - this.translationNotFoundIndicator = function (indicator) { - this.translationNotFoundIndicatorLeft(indicator); - this.translationNotFoundIndicatorRight(indicator); - return this; - }; - this.translationNotFoundIndicatorLeft = function (indicator) { - if (!indicator) { - return $notFoundIndicatorLeft; - } - $notFoundIndicatorLeft = indicator; - return this; - }; - this.translationNotFoundIndicatorRight = function (indicator) { - if (!indicator) { - return $notFoundIndicatorRight; - } - $notFoundIndicatorRight = indicator; - return this; - }; - this.fallbackLanguage = function (langKey) { - if (langKey) { - if (typeof langKey === 'string' || angular.isArray(langKey)) { - $fallbackLanguage = langKey; - } else { - } - return this; - } else { - return $fallbackLanguage; - } - }; - this.uses = function (langKey) { - if (langKey) { - if (!$translationTable[langKey] && !$loaderFactory) { - throw new Error('$translateProvider couldn\'t find translationTable for langKey: \'' + langKey + '\''); - } - $uses = langKey; - return this; - } else { - return $uses; - } - }; - var storageKey = function (key) { - if (!key) { - if ($storagePrefix) { - return $storagePrefix + $storageKey; - } - return $storageKey; - } - $storageKey = key; - }; - this.storageKey = storageKey; - this.useUrlLoader = function (url) { - return this.useLoader('$translateUrlLoader', { url: url }); - }; - this.useStaticFilesLoader = function (options) { - return this.useLoader('$translateStaticFilesLoader', options); - }; - this.useLoader = function (loaderFactory, options) { - $loaderFactory = loaderFactory; - $loaderOptions = options || {}; - return this; - }; - this.useLocalStorage = function () { - return this.useStorage('$translateLocalStorage'); - }; - this.useCookieStorage = function () { - return this.useStorage('$translateCookieStorage'); - }; - this.useStorage = function (storageFactory) { - $storageFactory = storageFactory; - return this; - }; - this.storagePrefix = function (prefix) { - if (!prefix) { - return prefix; - } - $storagePrefix = prefix; - return this; - }; - this.useMissingTranslationHandlerLog = function () { - return this.useMissingTranslationHandler('$translateMissingTranslationHandlerLog'); - }; - this.useMissingTranslationHandler = function (factory) { - $missingTranslationHandlerFactory = factory; - return this; - }; - this.$get = [ - '$log', - '$injector', - '$rootScope', - '$q', - function ($log, $injector, $rootScope, $q) { - var Storage, defaultInterpolator = $injector.get($interpolationFactory || '$translateDefaultInterpolation'), pendingLoader = false, interpolatorHashMap = {}; - var loadAsync = function (key) { - if (!key) { - throw 'No language key specified for loading.'; - } - var deferred = $q.defer(); - $rootScope.$broadcast('$translateLoadingStart'); - pendingLoader = true; - $injector.get($loaderFactory)(angular.extend($loaderOptions, { key: key })).then(function (data) { - $rootScope.$broadcast('$translateLoadingSuccess'); - var translationTable = {}; - if (angular.isArray(data)) { - angular.forEach(data, function (table) { - angular.extend(translationTable, table); - }); - } else { - angular.extend(translationTable, data); - } - pendingLoader = false; - deferred.resolve({ - key: key, - table: translationTable - }); - $rootScope.$broadcast('$translateLoadingEnd'); - }, function (key) { - $rootScope.$broadcast('$translateLoadingError'); - deferred.reject(key); - $rootScope.$broadcast('$translateLoadingEnd'); - }); - return deferred.promise; - }; - if ($storageFactory) { - Storage = $injector.get($storageFactory); - if (!Storage.get || !Storage.set) { - throw new Error('Couldn\'t use storage \'' + $storageFactory + '\', missing get() or set() method!'); - } - } - if ($interpolatorFactories.length > 0) { - angular.forEach($interpolatorFactories, function (interpolatorFactory) { - var interpolator = $injector.get(interpolatorFactory); - interpolator.setLocale($preferredLanguage || $uses); - interpolatorHashMap[interpolator.getInterpolationIdentifier()] = interpolator; - }); - } - var checkValidFallback = function (usesLang) { - if (usesLang && $fallbackLanguage) { - if (angular.isArray($fallbackLanguage)) { - var fallbackLanguagesSize = $fallbackLanguage.length; - for (var current = 0; current < fallbackLanguagesSize; current++) { - if ($uses === $translationTable[$fallbackLanguage[current]]) { - return false; - } - } - return true; - } else { - return usesLang !== $fallbackLanguage; - } - } else { - return false; - } - return false; - }; - var $translate = function (translationId, interpolateParams, interpolationId) { - var table = $uses ? $translationTable[$uses] : $translationTable, Interpolator = interpolationId ? interpolatorHashMap[interpolationId] : defaultInterpolator; - if (table && table.hasOwnProperty(translationId)) { - if (angular.isString(table[translationId]) && table[translationId].substr(0, 2) === '@:') { - return $translate(table[translationId].substr(2), interpolateParams, interpolationId); - } - return Interpolator.interpolate(table[translationId], interpolateParams); - } - if ($missingTranslationHandlerFactory && !pendingLoader) { - $injector.get($missingTranslationHandlerFactory)(translationId, $uses); - } - var normatedLanguages; - if ($uses && $fallbackLanguage && checkValidFallback($uses)) { - if (typeof $fallbackLanguage === 'string') { - normatedLanguages = []; - normatedLanguages.push($fallbackLanguage); - } else { - normatedLanguages = $fallbackLanguage; - } - var fallbackLanguagesSize = normatedLanguages.length; - for (var current = 0; current < fallbackLanguagesSize; current++) { - if ($uses !== $translationTable[normatedLanguages[current]]) { - var translationFromList = $translationTable[normatedLanguages[current]][translationId]; - if (translationFromList) { - var returnValFromList; - Interpolator.setLocale(normatedLanguages[current]); - returnValFromList = Interpolator.interpolate(translationFromList, interpolateParams); - Interpolator.setLocale($uses); - return returnValFromList; - } - } - } - } - if ($notFoundIndicatorLeft) { - translationId = [ - $notFoundIndicatorLeft, - translationId - ].join(' '); - } - if ($notFoundIndicatorRight) { - translationId = [ - translationId, - $notFoundIndicatorRight - ].join(' '); - } - return translationId; - }; - $translate.preferredLanguage = function () { - return $preferredLanguage; - }; - $translate.fallbackLanguage = function () { - return $fallbackLanguage; - }; - $translate.proposedLanguage = function () { - return $nextLang; - }; - $translate.storage = function () { - return Storage; - }; - $translate.uses = function (key) { - if (!key) { - return $uses; - } - var deferred = $q.defer(); - $rootScope.$broadcast('$translateChangeStart'); - function useLanguage(key) { - $uses = key; - $rootScope.$broadcast('$translateChangeSuccess'); - if ($storageFactory) { - Storage.set($translate.storageKey(), $uses); - } - defaultInterpolator.setLocale($uses); - angular.forEach(interpolatorHashMap, function (interpolator, id) { - interpolatorHashMap[id].setLocale($uses); - }); - deferred.resolve(key); - $rootScope.$broadcast('$translateChangeEnd'); - } - if (!$translationTable[key] && $loaderFactory) { - $nextLang = key; - loadAsync(key).then(function (translation) { - $nextLang = undefined; - translations(translation.key, translation.table); - useLanguage(translation.key); - }, function (key) { - $nextLang = undefined; - $rootScope.$broadcast('$translateChangeError'); - deferred.reject(key); - $rootScope.$broadcast('$translateChangeEnd'); - }); - } else { - useLanguage(key); - } - return deferred.promise; - }; - $translate.storageKey = function () { - return storageKey(); - }; - $translate.refresh = function (langKey) { - if (!$loaderFactory) { - throw new Error('Couldn\'t refresh translation table, no loader registered!'); - } - var deferred = $q.defer(); - function onLoadSuccess() { - deferred.resolve(); - $rootScope.$broadcast('$translateRefreshEnd'); - } - function onLoadFailure() { - deferred.reject(); - $rootScope.$broadcast('$translateRefreshEnd'); - } - if (!langKey) { - $rootScope.$broadcast('$translateRefreshStart'); - var loaders = []; - if ($fallbackLanguage) { - if (typeof $fallbackLanguage === 'string') { - loaders.push(loadAsync($fallbackLanguage)); - } else { - var fallbackLanguagesSize = $fallbackLanguage.length; - for (var current = 0; current < fallbackLanguagesSize; current++) { - loaders.push(loadAsync($fallbackLanguage[current])); - } - } - } - if ($uses) { - loaders.push(loadAsync($uses)); - } - if (loaders.length > 0) { - $q.all(loaders).then(function (newTranslations) { - for (var lang in $translationTable) { - if ($translationTable.hasOwnProperty(lang)) { - delete $translationTable[lang]; - } - } - for (var i = 0, len = newTranslations.length; i < len; i++) { - translations(newTranslations[i].key, newTranslations[i].table); - } - if ($uses) { - $translate.uses($uses); - } - onLoadSuccess(); - }, function (key) { - if (key === $uses) { - $rootScope.$broadcast('$translateChangeError'); - } - onLoadFailure(); - }); - } else - onLoadSuccess(); - } else if ($translationTable.hasOwnProperty(langKey)) { - $rootScope.$broadcast('$translateRefreshStart'); - var loader = loadAsync(langKey); - if (langKey === $uses) { - loader.then(function (newTranslation) { - $translationTable[langKey] = newTranslation.table; - $translate.uses($uses); - onLoadSuccess(); - }, function () { - $rootScope.$broadcast('$translateChangeError'); - onLoadFailure(); - }); - } else { - loader.then(function (newTranslation) { - $translationTable[langKey] = newTranslation.table; - onLoadSuccess(); - }, onLoadFailure); - } - } else - deferred.reject(); - return deferred.promise; - }; - if ($loaderFactory) { - if (angular.equals($translationTable, {})) { - $translate.uses($translate.uses()); - } - if ($fallbackLanguage) { - if (typeof $fallbackLanguage === 'string' && !$translationTable[$fallbackLanguage]) { - loadAsync($fallbackLanguage); - } else { - var fallbackLanguagesSize = $fallbackLanguage.length; - for (var current = 0; current < fallbackLanguagesSize; current++) { - if (!$translationTable[$fallbackLanguage[current]]) { - loadAsync($fallbackLanguage[current]); - } - } - } - } - } - return $translate; - } - ]; - } -]); -angular.module('pascalprecht.translate').factory('$translateDefaultInterpolation', [ - '$interpolate', - function ($interpolate) { - var $translateInterpolator = {}, $locale, $identifier = 'default'; - $translateInterpolator.setLocale = function (locale) { - $locale = locale; - }; - $translateInterpolator.getInterpolationIdentifier = function () { - return $identifier; - }; - $translateInterpolator.interpolate = function (string, interpolateParams) { - return $interpolate(string)(interpolateParams); - }; - return $translateInterpolator; - } -]); -angular.module('pascalprecht.translate').constant('$STORAGE_KEY', 'NG_TRANSLATE_LANG_KEY'); -angular.module('pascalprecht.translate').directive('translate', [ - '$filter', - '$interpolate', - '$parse', - function ($filter, $interpolate, $parse) { - var translate = $filter('translate'); - return { - restrict: 'AE', - scope: true, - link: function linkFn(scope, element, attr) { - if (attr.translateInterpolation) { - scope.interpolation = attr.translateInterpolation; - } - attr.$observe('translate', function (translationId) { - if (angular.equals(translationId, '') || translationId === undefined) { - scope.translationId = $interpolate(element.text().replace(/^\s+|\s+$/g, ''))(scope.$parent); - } else { - scope.translationId = translationId; - } - }); - attr.$observe('translateValues', function (interpolateParams) { - if (interpolateParams) - scope.$parent.$watch(function () { - scope.interpolateParams = $parse(interpolateParams)(scope.$parent); - }); - }); - scope.$on('$translateChangeSuccess', function () { - element.html(translate(scope.translationId, scope.interpolateParams, scope.interpolation)); - }); - scope.$watch('[translationId, interpolateParams]', function (nValue) { - if (scope.translationId) { - element.html(translate(scope.translationId, scope.interpolateParams, scope.interpolation)); - } - }, true); - } - }; - } -]); -angular.module('pascalprecht.translate').filter('translate', [ - '$parse', - '$translate', - function ($parse, $translate) { - return function (translationId, interpolateParams, interpolation) { - if (!angular.isObject(interpolateParams)) { - interpolateParams = $parse(interpolateParams)(); - } - return $translate(translationId, interpolateParams, interpolation); - }; - } -]); -angular.module('pascalprecht.translate').factory('$translateStaticFilesLoader', [ - '$q', - '$http', - function ($q, $http) { - return function (options) { - if (!options || (!options.prefix || !options.suffix)) { - throw new Error('Couldn\'t load static files, no prefix or suffix specified!'); - } - var deferred = $q.defer(); - $http({ - url: [ - options.prefix, - options.key, - options.suffix - ].join(''), - method: 'GET', - params: '' - }).success(function (data) { - deferred.resolve(data); - }).error(function (data) { - deferred.reject(options.key); - }); - return deferred.promise; - }; - } -]); -/*! Kaltura Embed Code Generator - v1.0.6 - 2013-02-28 -* https://github.com/kaltura/EmbedCodeGenerator -* Copyright (c) 2013 Ran Yefet; Licensed MIT */ - -// lib/handlebars/base.js - -/*jshint eqnull:true*/ -this.Handlebars = {}; - -(function(Handlebars) { - -Handlebars.VERSION = "1.0.rc.2"; - -Handlebars.helpers = {}; -Handlebars.partials = {}; - -Handlebars.registerHelper = function(name, fn, inverse) { - if(inverse) { fn.not = inverse; } - this.helpers[name] = fn; -}; - -Handlebars.registerPartial = function(name, str) { - this.partials[name] = str; -}; - -Handlebars.registerHelper('helperMissing', function(arg) { - if(arguments.length === 2) { - return undefined; - } else { - throw new Error("Could not find property '" + arg + "'"); - } -}); - -var toString = Object.prototype.toString, functionType = "[object Function]"; - -Handlebars.registerHelper('blockHelperMissing', function(context, options) { - var inverse = options.inverse || function() {}, fn = options.fn; - - - var ret = ""; - var type = toString.call(context); - - if(type === functionType) { context = context.call(this); } - - if(context === true) { - return fn(this); - } else if(context === false || context == null) { - return inverse(this); - } else if(type === "[object Array]") { - if(context.length > 0) { - return Handlebars.helpers.each(context, options); - } else { - return inverse(this); - } - } else { - return fn(context); - } -}); - -Handlebars.K = function() {}; - -Handlebars.createFrame = Object.create || function(object) { - Handlebars.K.prototype = object; - var obj = new Handlebars.K(); - Handlebars.K.prototype = null; - return obj; -}; - -Handlebars.logger = { - DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3, - - methodMap: {0: 'debug', 1: 'info', 2: 'warn', 3: 'error'}, - - // can be overridden in the host environment - log: function(level, obj) { - if (Handlebars.logger.level <= level) { - var method = Handlebars.logger.methodMap[level]; - if (typeof console !== 'undefined' && console[method]) { - console[method].call(console, obj); - } - } - } -}; - -Handlebars.log = function(level, obj) { Handlebars.logger.log(level, obj); }; - -Handlebars.registerHelper('each', function(context, options) { - var fn = options.fn, inverse = options.inverse; - var i = 0, ret = "", data; - - if (options.data) { - data = Handlebars.createFrame(options.data); - } - - if(context && typeof context === 'object') { - if(context instanceof Array){ - for(var j = context.length; i": ">", - '"': """, - "'": "'", - "`": "`" - }; - - var badChars = /[&<>"'`]/g; - var possible = /[&<>"'`]/; - - var escapeChar = function(chr) { - return escape[chr] || "&"; - }; - - Handlebars.Utils = { - escapeExpression: function(string) { - // don't escape SafeStrings, since they're already safe - if (string instanceof Handlebars.SafeString) { - return string.toString(); - } else if (string == null || string === false) { - return ""; - } - - if(!possible.test(string)) { return string; } - return string.replace(badChars, escapeChar); - }, - - isEmpty: function(value) { - if (!value && value !== 0) { - return true; - } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) { - return true; - } else { - return false; - } - } - }; -})();; -// lib/handlebars/runtime.js -Handlebars.VM = { - template: function(templateSpec) { - // Just add water - var container = { - escapeExpression: Handlebars.Utils.escapeExpression, - invokePartial: Handlebars.VM.invokePartial, - programs: [], - program: function(i, fn, data) { - var programWrapper = this.programs[i]; - if(data) { - return Handlebars.VM.program(fn, data); - } else if(programWrapper) { - return programWrapper; - } else { - programWrapper = this.programs[i] = Handlebars.VM.program(fn); - return programWrapper; - } - }, - programWithDepth: Handlebars.VM.programWithDepth, - noop: Handlebars.VM.noop - }; - - return function(context, options) { - options = options || {}; - return templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data); - }; - }, - - programWithDepth: function(fn, data, $depth) { - var args = Array.prototype.slice.call(arguments, 2); - - return function(context, options) { - options = options || {}; - - return fn.apply(this, [context, options.data || data].concat(args)); - }; - }, - program: function(fn, data) { - return function(context, options) { - options = options || {}; - - return fn(context, options.data || data); - }; - }, - noop: function() { return ""; }, - invokePartial: function(partial, name, context, helpers, partials, data) { - var options = { helpers: helpers, partials: partials, data: data }; - - if(partial === undefined) { - throw new Handlebars.Exception("The partial " + name + " could not be found"); - } else if(partial instanceof Function) { - return partial(context, options); - } else if (!Handlebars.compile) { - throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in runtime-only mode"); - } else { - partials[name] = Handlebars.compile(partial, {data: data !== undefined}); - return partials[name](context, options); - } - } -}; - -Handlebars.template = Handlebars.VM.template; -; - -(function (window, Handlebars, undefined ) { -/** -* Transforms flashVars object into a string for Url or Flashvars string. -* -* @method flashVarsToUrl -* @param {Object} flashVarsObject A flashvars object -* @param {String} paramName The name parameter to add to url -* @return {String} Returns flashVars string like: &foo=bar or ¶m[foo]=bar -*/ -var flashVarsToUrl = function( flashVarsObject, paramName ) { - var params = ''; - - var paramPrefix = (paramName) ? paramName + '[' : ''; - var paramSuffix = (paramName) ? ']' : ''; - - for( var i in flashVarsObject ){ - // check for object representation of plugin config: - if( typeof flashVarsObject[i] == 'object' ){ - for( var j in flashVarsObject[i] ){ - params+= '&' + paramPrefix + encodeURIComponent( i ) + - '.' + encodeURIComponent( j ) + paramSuffix + - '=' + encodeURIComponent( flashVarsObject[i][j] ); - } - } else { - params+= '&' + paramPrefix + encodeURIComponent( i ) + paramSuffix + '=' + encodeURIComponent( flashVarsObject[i] ); - } - } - return params; -}; - -// Setup handlebars helpers -Handlebars.registerHelper('flashVarsUrl', function(flashVars) { - return flashVarsToUrl(flashVars, 'flashvars'); -}); -Handlebars.registerHelper('flashVarsString', function(flashVars) { - return flashVarsToUrl(flashVars); -}); -Handlebars.registerHelper('elAttributes', function( attributes ) { - var str = ''; - for( var i in attributes ) { - str += ' ' + i + '="' + attributes[i] + '"'; - } - return str; -}); -// Include kaltura links -Handlebars.registerHelper('kalturaLinks', function() { - if( ! this.includeKalturaLinks ) { - return ''; - } - var template = Handlebars.templates['kaltura_links']; - return template(); -}); - -Handlebars.registerHelper('seoMetadata', function() { - var template = Handlebars.templates['seo_metadata']; - return template(this); -}); - -})(this, this.Handlebars); -(function(){var a=Handlebars.template,b=Handlebars.templates=Handlebars.templates||{};b.auto=a(function(a,b,c,d,e){function p(a,b){var d="",e,f;d+='
",i=c.seoMetadata,e=i||a.seoMetadata,typeof e===l?e=e.call(a,{hash:{}}):e===n&&(e=m.call(a,"seoMetadata",{hash:{}}));if(e||e===0)d+=e;i=c.kalturaLinks,e=i||a.kalturaLinks,typeof e===l?e=e.call(a,{hash:{}}):e===n&&(e=m.call(a,"kalturaLinks",{hash:{}}));if(e||e===0)d+=e;return d+="
\n",d}function q(a,b){var d="",e;return d+="&entry_id=",i=c.entryId,e=i||a.entryId,typeof e===l?e=e.call(a,{hash:{}}):e===n&&(e=m.call(a,"entryId",{hash:{}})),d+=o(e),d}function r(a,b){var d="",e;return d+="&cache_st=",i=c.cacheSt,e=i||a.cacheSt,typeof e===l?e=e.call(a,{hash:{}}):e===n&&(e=m.call(a,"cacheSt",{hash:{}})),d+=o(e),d}c=c||a.helpers;var f="",g,h,i,j,k=this,l="function",m=c.helperMissing,n=void 0,o=this.escapeExpression;i=c.includeSeoMetadata,g=i||b.includeSeoMetadata,h=c["if"],j=k.program(1,p,e),j.hash={},j.fn=j,j.inverse=k.noop,g=h.call(b,g,j);if(g||g===0)f+=g;f+='\n
",i=c.seoMetadata,g=i||b.seoMetadata,typeof g===k?g=g.call(b,{hash:{}}):g===m&&(g=l.call(b,"seoMetadata",{hash:{}}));if(g||g===0)f+=g;i=c.kalturaLinks,g=i||b.kalturaLinks,typeof g===k?g=g.call(b,{hash:{}}):g===m&&(g=l.call(b,"kalturaLinks",{hash:{}}));if(g||g===0)f+=g;f+="
\n",f}),b.iframe=a(function(a,b,c,d,e){function p(a,b){var d="",e;return d+="&entry_id=",i=c.entryId,e=i||a.entryId,typeof e===l?e=e.call(a,{hash:{}}):e===n&&(e=m.call(a,"entryId",{hash:{}})),d+=o(e),d}c=c||a.helpers;var f="",g,h,i,j,k=this,l="function",m=c.helperMissing,n=void 0,o=this.escapeExpression;f+='",f}),b.kaltura_links=a(function(a,b,c,d,e){c=c||a.helpers;var f,g=this;return'Video Platform\nVideo Management \nVideo Solutions\nVideo Player'}),b.legacy=a(function(a,b,c,d,e){function p(a,b){var d="",e;return d+='\n',d}function q(a,b){var d="",e;return d+='\n \n \n \n \n \n \n ',d}c=c||a.helpers;var f="",g,h,i,j,k=this,l="function",m=c.helperMissing,n=void 0,o=this.escapeExpression;i=c.includeHtml5Library,g=i||b.includeHtml5Library,h=c["if"],j=k.program(1,p,e),j.hash={},j.fn=j,j.inverse=k.noop,g=h.call(b,g,j);if(g||g===0)f+=g;f+='\n \n \n \n \n \n \n ',i=c.includeSeoMetadata,g=i||b.includeSeoMetadata,h=c["if"],j=k.program(3,q,e),j.hash={},j.fn=j,j.inverse=k.noop,g=h.call(b,g,j);if(g||g===0)f+=g;i=c.kalturaLinks,g=i||b.kalturaLinks,typeof g===l?g=g.call(b,{hash:{}}):g===n&&(g=m.call(b,"kalturaLinks",{hash:{}}));if(g||g===0)f+=g;return f+="\n",f}),b.seo_metadata=a(function(a,b,c,d,e){function o(a,b){var d="",e;return d+='\n\n\n\n\n\n\n',d}c=c||a.helpers;var f,g,h,i,j=this,k="function",l=c.helperMissing,m=void 0,n=this.escapeExpression;return h=c.includeSeoMetadata,f=h||b.includeSeoMetadata,g=c["if"],i=j.program(1,o,e),i.hash={},i.fn=i,i.inverse=j.noop,f=g.call(b,f,i),f||f===0?f:""})})() -// Add indexOf to array object -if (!Array.prototype.indexOf) { - Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { - "use strict"; - if (this == null) { - throw new TypeError(); - } - var t = Object(this); - var len = t.length >>> 0; - if (len === 0) { - return -1; - } - var n = 0; - if (arguments.length > 1) { - n = Number(arguments[1]); - if (n !== n) { // shortcut for verifying if it's NaN - n = 0; - } else if (n !== 0 && n !== Infinity && n !== -Infinity) { - n = (n > 0 || -1) * Math.floor(Math.abs(n)); - } - } - if (n >= len) { - return -1; - } - var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); - for (; k < len; k++) { - if (k in t && t[k] === searchElement) { - return k; - } - } - return -1; - }; -} -// Add keys for Object -if (!Object.keys) { - Object.keys = (function () { - var hasOwnProperty = Object.prototype.hasOwnProperty, - hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), - dontEnums = [ - 'toString', - 'toLocaleString', - 'valueOf', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'constructor' - ], - dontEnumsLength = dontEnums.length; - - return function (obj) { - if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) { - throw new TypeError('Object.keys called on non-object'); - } - - var result = []; - - for (var prop in obj) { - if (hasOwnProperty.call(obj, prop)) { - result.push(prop); - } - } - - if (hasDontEnumBug) { - for (var i=0; i < dontEnumsLength; i++) { - if (hasOwnProperty.call(obj, dontEnums[i])) { - result.push(dontEnums[i]); - } - } - } - return result; - }; - })(); -} -(function( window, undefined ) { -/** -* Kaltura Embed Code Generator -* Used to generate different type of embed codes -* Depended on Handlebars ( http://handlebarsjs.com/ ) -* -* @class EmbedCodeGenerator -* @constructor -*/ -var EmbedCodeGenerator = function( options ) { - this.init( options ); -}; - -EmbedCodeGenerator.prototype = { - - types: ['auto', 'dynamic', 'thumb', 'iframe', 'legacy'], - required: ['widgetId', 'partnerId', 'uiConfId'], - - defaults: { - /** - * Embed code type to generate - * Can we one of: ['auto', 'dynamic', 'thumb', 'iframe', 'legacy'] - * - * @property embedType - * @type {String} - * @default "auto" - */ - embedType: 'auto', - /** - * The Player element Id / Name that will be used for embed code - * - * @property playerId - * @type {String} - * @default "kaltura_player" - */ - playerId: 'kaltura_player', - /** - * Embed HTTP protocol to use - * Can we one of: ['http', 'https'] - * - * @property protocol - * @type {String} - * @default "http" - */ - protocol: 'http', - /** - * Host for loading html5 library & kdp swf - * - * @property host - * @type {String} - * @default "www.kaltura.com" - */ - host: 'www.kaltura.com', - /** - * Secured host for loading html5 library & kdp swf - * Used if protocol is: 'https' - * - * @property securedHost - * @type {String} - * @default "www.kaltura.com" - */ - securedHost: 'www.kaltura.com', - /** - * Kaltura Widget Id - * - * @property widgetId - * @type {String} - * @default "_{partnerId}" - */ - widgetId: null, - /** - * Kaltura Partner Id - * - * @property partnerId - * @type {Number} - * @default null, - */ - partnerId: null, - /** - * Add cacheSt parameter to bust cache - * Should be unix timestamp of future time - * - * @property cacheSt - * @type {Number} - * @default null, - */ - cacheSt: null, - /** - * Kaltura UiConf Id - * - * @property uiConfId - * @type {Number} - * @default null, - */ - uiConfId: null, - /** - * Kaltura Entry Id - * - * @property entryId - * @type {String} - * @default null, - */ - entryId: null, - /** - * Entry Object similar to: - * { - * name: 'Foo', - * description: 'Bar', - * thumbUrl: 'http://cdnbakmi.kaltura.com/thumbnail/...' - * } - * - * @property entryMeta - * @type {Object} - * @default {}, - */ - entryMeta: {}, - /** - * Sets Player Width - * - * @property width - * @type {Number} - * @default 400, - */ - width: 400, - /** - * Sets Player Height - * - * @property height - * @type {Number} - * @default 330, - */ - height: 330, - /** - * Adds additonal attributes to embed code. - * Example: - * { - * "class": "player" - * } - * - * @property attributes - * @type {Object} - * @default {}, - */ - attributes: {}, - /** - * Adds flashVars to player - * Example: - * { - * "autoPlay": "true" - * } - * - * @property flashVars - * @type {Object} - * @default {}, - */ - flashVars: {}, - /** - * Include Kaltura SEO links to embed code - * - * @property includeKalturaLinks - * @type {Boolean} - * @default true, - */ - includeKalturaLinks: true, - /** - * Include Entry Seo Metadata - * Metadata is taken from {entryMeta} object - * - * @property includeSeoMetadata - * @type {Boolean} - * @default false, - */ - includeSeoMetadata: false, - /** - * Include HTML5 library script - * - * @property includeHtml5Library - * @type {Boolean} - * @default true, - */ - includeHtml5Library: true - }, - /** - * Merge two object together - * - * @method extend - * @param {Object} destination object to merge into - * @param {Object} sourece object to merge from - * @return {Object} Merged object - */ - extend: function(destination, source) { - for (var property in source) { - if (source.hasOwnProperty(property) && !destination.hasOwnProperty(property)) { - destination[property] = source[property]; - } - } - return destination; - }, - /** - * Check if property is null - * - * @method isNull - * @param {Any} property some var - * @return {Boolean} - */ - isNull: function( property ) { - if (property.length && property.length > 0) { - return false; - } - if (property.length && property.length === 0) { - return true; - } - if( typeof property === 'object' ) { - return (Object.keys(property).length > 0) ? false : true; - } - return !property; - }, - /** - * Set default options to EmbedCodeGenerator instance - * - * @method init - * @param {Object} options Configuration object based on defaults object - * @return {Object} Returns the current instance - */ - init: function( options ) { - - options = options || {}; - - var defaults = this.defaults; - - // Make sure Handlebars is available - if( typeof Handlebars === undefined ) { - throw 'Handlebars is not defined, please include Handlebars.js before this script'; - } - - // Merge options with defaults - if( typeof options === 'object' ) { - this.options = this.extend(options, this.defaults); - } - // Set widgetId to partnerId if not defined - if( ! this.config('widgetId') && this.config('partnerId') ) { - this.config('widgetId', '_' + this.config('partnerId')); - } - - return this; - }, - /** - * Get or Set default configuration - * - * @method config - * @param {String} key configuration property name - * @param {Any} value to set - * @return {Mixed} Return the value for the key, configuration object or null - */ - config: function( key, val ) { - // Used as getter - if( val === undefined && typeof key === 'string' && this.options.hasOwnProperty(key) ) { - return this.options[ key ]; - } - // Get all options - if( key === undefined && val === undefined ) { - return this.options; - } - // Used as setter - if( typeof key === 'string' && val !== undefined ) { - this.options[ key ] = val; - } - return null; - }, - /** - * Check if required parameters are missing - * - * @method checkRequiredParams - * @param {Object} Configuration object - * @return throws exception if missing parameters - */ - checkRequiredParams: function( params ) { - var requiredLength = this.required.length, - i = 0; - // Check for required configuration - for(i; i 0) { + angular.forEach($interpolatorFactories, function (interpolatorFactory) { + var interpolator = $injector.get(interpolatorFactory); + interpolator.setLocale($preferredLanguage || $uses); + interpolatorHashMap[interpolator.getInterpolationIdentifier()] = interpolator; + }); + } + var checkValidFallback = function (usesLang) { + if (usesLang && $fallbackLanguage) { + if (angular.isArray($fallbackLanguage)) { + var fallbackLanguagesSize = $fallbackLanguage.length; + for (var current = 0; current < fallbackLanguagesSize; current++) { + if ($uses === $translationTable[$fallbackLanguage[current]]) { + return false; + } + } + return true; + } else { + return usesLang !== $fallbackLanguage; + } + } else { + return false; + } + return false; + }; + var $translate = function (translationId, interpolateParams, interpolationId) { + var table = $uses ? $translationTable[$uses] : $translationTable, Interpolator = interpolationId ? interpolatorHashMap[interpolationId] : defaultInterpolator; + if (table && table.hasOwnProperty(translationId)) { + if (angular.isString(table[translationId]) && table[translationId].substr(0, 2) === '@:') { + return $translate(table[translationId].substr(2), interpolateParams, interpolationId); + } + return Interpolator.interpolate(table[translationId], interpolateParams); + } + if ($missingTranslationHandlerFactory && !pendingLoader) { + $injector.get($missingTranslationHandlerFactory)(translationId, $uses); + } + var normatedLanguages; + if ($uses && $fallbackLanguage && checkValidFallback($uses)) { + if (typeof $fallbackLanguage === 'string') { + normatedLanguages = []; + normatedLanguages.push($fallbackLanguage); + } else { + normatedLanguages = $fallbackLanguage; + } + var fallbackLanguagesSize = normatedLanguages.length; + for (var current = 0; current < fallbackLanguagesSize; current++) { + if ($uses !== $translationTable[normatedLanguages[current]]) { + var translationFromList = $translationTable[normatedLanguages[current]][translationId]; + if (translationFromList) { + var returnValFromList; + Interpolator.setLocale(normatedLanguages[current]); + returnValFromList = Interpolator.interpolate(translationFromList, interpolateParams); + Interpolator.setLocale($uses); + return returnValFromList; + } + } + } + } + if ($notFoundIndicatorLeft) { + translationId = [ + $notFoundIndicatorLeft, + translationId + ].join(' '); + } + if ($notFoundIndicatorRight) { + translationId = [ + translationId, + $notFoundIndicatorRight + ].join(' '); + } + return translationId; + }; + $translate.preferredLanguage = function () { + return $preferredLanguage; + }; + $translate.fallbackLanguage = function () { + return $fallbackLanguage; + }; + $translate.proposedLanguage = function () { + return $nextLang; + }; + $translate.storage = function () { + return Storage; + }; + $translate.uses = function (key) { + if (!key) { + return $uses; + } + var deferred = $q.defer(); + $rootScope.$broadcast('$translateChangeStart'); + function useLanguage(key) { + $uses = key; + $rootScope.$broadcast('$translateChangeSuccess'); + if ($storageFactory) { + Storage.set($translate.storageKey(), $uses); + } + defaultInterpolator.setLocale($uses); + angular.forEach(interpolatorHashMap, function (interpolator, id) { + interpolatorHashMap[id].setLocale($uses); + }); + deferred.resolve(key); + $rootScope.$broadcast('$translateChangeEnd'); + } + if (!$translationTable[key] && $loaderFactory) { + $nextLang = key; + loadAsync(key).then(function (translation) { + $nextLang = undefined; + translations(translation.key, translation.table); + useLanguage(translation.key); + }, function (key) { + $nextLang = undefined; + $rootScope.$broadcast('$translateChangeError'); + deferred.reject(key); + $rootScope.$broadcast('$translateChangeEnd'); + }); + } else { + useLanguage(key); + } + return deferred.promise; + }; + $translate.storageKey = function () { + return storageKey(); + }; + $translate.refresh = function (langKey) { + if (!$loaderFactory) { + throw new Error('Couldn\'t refresh translation table, no loader registered!'); + } + var deferred = $q.defer(); + function onLoadSuccess() { + deferred.resolve(); + $rootScope.$broadcast('$translateRefreshEnd'); + } + function onLoadFailure() { + deferred.reject(); + $rootScope.$broadcast('$translateRefreshEnd'); + } + if (!langKey) { + $rootScope.$broadcast('$translateRefreshStart'); + var loaders = []; + if ($fallbackLanguage) { + if (typeof $fallbackLanguage === 'string') { + loaders.push(loadAsync($fallbackLanguage)); + } else { + var fallbackLanguagesSize = $fallbackLanguage.length; + for (var current = 0; current < fallbackLanguagesSize; current++) { + loaders.push(loadAsync($fallbackLanguage[current])); + } + } + } + if ($uses) { + loaders.push(loadAsync($uses)); + } + if (loaders.length > 0) { + $q.all(loaders).then(function (newTranslations) { + for (var lang in $translationTable) { + if ($translationTable.hasOwnProperty(lang)) { + delete $translationTable[lang]; + } + } + for (var i = 0, len = newTranslations.length; i < len; i++) { + translations(newTranslations[i].key, newTranslations[i].table); + } + if ($uses) { + $translate.uses($uses); + } + onLoadSuccess(); + }, function (key) { + if (key === $uses) { + $rootScope.$broadcast('$translateChangeError'); + } + onLoadFailure(); + }); + } else + onLoadSuccess(); + } else if ($translationTable.hasOwnProperty(langKey)) { + $rootScope.$broadcast('$translateRefreshStart'); + var loader = loadAsync(langKey); + if (langKey === $uses) { + loader.then(function (newTranslation) { + $translationTable[langKey] = newTranslation.table; + $translate.uses($uses); + onLoadSuccess(); + }, function () { + $rootScope.$broadcast('$translateChangeError'); + onLoadFailure(); + }); + } else { + loader.then(function (newTranslation) { + $translationTable[langKey] = newTranslation.table; + onLoadSuccess(); + }, onLoadFailure); + } + } else + deferred.reject(); + return deferred.promise; + }; + if ($loaderFactory) { + if (angular.equals($translationTable, {})) { + $translate.uses($translate.uses()); + } + if ($fallbackLanguage) { + if (typeof $fallbackLanguage === 'string' && !$translationTable[$fallbackLanguage]) { + loadAsync($fallbackLanguage); + } else { + var fallbackLanguagesSize = $fallbackLanguage.length; + for (var current = 0; current < fallbackLanguagesSize; current++) { + if (!$translationTable[$fallbackLanguage[current]]) { + loadAsync($fallbackLanguage[current]); + } + } + } + } + } + return $translate; + } + ]; + } +]); +angular.module('pascalprecht.translate').factory('$translateDefaultInterpolation', [ + '$interpolate', + function ($interpolate) { + var $translateInterpolator = {}, $locale, $identifier = 'default'; + $translateInterpolator.setLocale = function (locale) { + $locale = locale; + }; + $translateInterpolator.getInterpolationIdentifier = function () { + return $identifier; + }; + $translateInterpolator.interpolate = function (string, interpolateParams) { + return $interpolate(string)(interpolateParams); + }; + return $translateInterpolator; + } +]); +angular.module('pascalprecht.translate').constant('$STORAGE_KEY', 'NG_TRANSLATE_LANG_KEY'); +angular.module('pascalprecht.translate').directive('translate', [ + '$filter', + '$interpolate', + '$parse', + function ($filter, $interpolate, $parse) { + var translate = $filter('translate'); + return { + restrict: 'AE', + scope: true, + link: function linkFn(scope, element, attr) { + if (attr.translateInterpolation) { + scope.interpolation = attr.translateInterpolation; + } + attr.$observe('translate', function (translationId) { + if (angular.equals(translationId, '') || translationId === undefined) { + scope.translationId = $interpolate(element.text().replace(/^\s+|\s+$/g, ''))(scope.$parent); + } else { + scope.translationId = translationId; + } + }); + attr.$observe('translateValues', function (interpolateParams) { + if (interpolateParams) + scope.$parent.$watch(function () { + scope.interpolateParams = $parse(interpolateParams)(scope.$parent); + }); + }); + scope.$on('$translateChangeSuccess', function () { + element.html(translate(scope.translationId, scope.interpolateParams, scope.interpolation)); + }); + scope.$watch('[translationId, interpolateParams]', function (nValue) { + if (scope.translationId) { + element.html(translate(scope.translationId, scope.interpolateParams, scope.interpolation)); + } + }, true); + } + }; + } +]); +angular.module('pascalprecht.translate').filter('translate', [ + '$parse', + '$translate', + function ($parse, $translate) { + return function (translationId, interpolateParams, interpolation) { + if (!angular.isObject(interpolateParams)) { + interpolateParams = $parse(interpolateParams)(); + } + return $translate(translationId, interpolateParams, interpolation); + }; + } +]); +angular.module('pascalprecht.translate').factory('$translateStaticFilesLoader', [ + '$q', + '$http', + function ($q, $http) { + return function (options) { + if (!options || (!options.prefix || !options.suffix)) { + throw new Error('Couldn\'t load static files, no prefix or suffix specified!'); + } + var deferred = $q.defer(); + $http({ + url: [ + options.prefix, + options.key, + options.suffix + ].join(''), + method: 'GET', + params: '' + }).success(function (data) { + deferred.resolve(data); + }).error(function (data) { + deferred.reject(options.key); + }); + return deferred.promise; + }; + } +]); +/*! Kaltura Embed Code Generator - v1.0.6 - 2013-02-28 +* https://github.com/kaltura/EmbedCodeGenerator +* Copyright (c) 2013 Ran Yefet; Licensed MIT */ + +// lib/handlebars/base.js + +/*jshint eqnull:true*/ +this.Handlebars = {}; + +(function(Handlebars) { + +Handlebars.VERSION = "1.0.rc.2"; + +Handlebars.helpers = {}; +Handlebars.partials = {}; + +Handlebars.registerHelper = function(name, fn, inverse) { + if(inverse) { fn.not = inverse; } + this.helpers[name] = fn; +}; + +Handlebars.registerPartial = function(name, str) { + this.partials[name] = str; +}; + +Handlebars.registerHelper('helperMissing', function(arg) { + if(arguments.length === 2) { + return undefined; + } else { + throw new Error("Could not find property '" + arg + "'"); + } +}); + +var toString = Object.prototype.toString, functionType = "[object Function]"; + +Handlebars.registerHelper('blockHelperMissing', function(context, options) { + var inverse = options.inverse || function() {}, fn = options.fn; + + + var ret = ""; + var type = toString.call(context); + + if(type === functionType) { context = context.call(this); } + + if(context === true) { + return fn(this); + } else if(context === false || context == null) { + return inverse(this); + } else if(type === "[object Array]") { + if(context.length > 0) { + return Handlebars.helpers.each(context, options); + } else { + return inverse(this); + } + } else { + return fn(context); + } +}); + +Handlebars.K = function() {}; + +Handlebars.createFrame = Object.create || function(object) { + Handlebars.K.prototype = object; + var obj = new Handlebars.K(); + Handlebars.K.prototype = null; + return obj; +}; + +Handlebars.logger = { + DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3, + + methodMap: {0: 'debug', 1: 'info', 2: 'warn', 3: 'error'}, + + // can be overridden in the host environment + log: function(level, obj) { + if (Handlebars.logger.level <= level) { + var method = Handlebars.logger.methodMap[level]; + if (typeof console !== 'undefined' && console[method]) { + console[method].call(console, obj); + } + } + } +}; + +Handlebars.log = function(level, obj) { Handlebars.logger.log(level, obj); }; + +Handlebars.registerHelper('each', function(context, options) { + var fn = options.fn, inverse = options.inverse; + var i = 0, ret = "", data; + + if (options.data) { + data = Handlebars.createFrame(options.data); + } + + if(context && typeof context === 'object') { + if(context instanceof Array){ + for(var j = context.length; i": ">", + '"': """, + "'": "'", + "`": "`" + }; + + var badChars = /[&<>"'`]/g; + var possible = /[&<>"'`]/; + + var escapeChar = function(chr) { + return escape[chr] || "&"; + }; + + Handlebars.Utils = { + escapeExpression: function(string) { + // don't escape SafeStrings, since they're already safe + if (string instanceof Handlebars.SafeString) { + return string.toString(); + } else if (string == null || string === false) { + return ""; + } + + if(!possible.test(string)) { return string; } + return string.replace(badChars, escapeChar); + }, + + isEmpty: function(value) { + if (!value && value !== 0) { + return true; + } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) { + return true; + } else { + return false; + } + } + }; +})();; +// lib/handlebars/runtime.js +Handlebars.VM = { + template: function(templateSpec) { + // Just add water + var container = { + escapeExpression: Handlebars.Utils.escapeExpression, + invokePartial: Handlebars.VM.invokePartial, + programs: [], + program: function(i, fn, data) { + var programWrapper = this.programs[i]; + if(data) { + return Handlebars.VM.program(fn, data); + } else if(programWrapper) { + return programWrapper; + } else { + programWrapper = this.programs[i] = Handlebars.VM.program(fn); + return programWrapper; + } + }, + programWithDepth: Handlebars.VM.programWithDepth, + noop: Handlebars.VM.noop + }; + + return function(context, options) { + options = options || {}; + return templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data); + }; + }, + + programWithDepth: function(fn, data, $depth) { + var args = Array.prototype.slice.call(arguments, 2); + + return function(context, options) { + options = options || {}; + + return fn.apply(this, [context, options.data || data].concat(args)); + }; + }, + program: function(fn, data) { + return function(context, options) { + options = options || {}; + + return fn(context, options.data || data); + }; + }, + noop: function() { return ""; }, + invokePartial: function(partial, name, context, helpers, partials, data) { + var options = { helpers: helpers, partials: partials, data: data }; + + if(partial === undefined) { + throw new Handlebars.Exception("The partial " + name + " could not be found"); + } else if(partial instanceof Function) { + return partial(context, options); + } else if (!Handlebars.compile) { + throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in runtime-only mode"); + } else { + partials[name] = Handlebars.compile(partial, {data: data !== undefined}); + return partials[name](context, options); + } + } +}; + +Handlebars.template = Handlebars.VM.template; +; + +(function (window, Handlebars, undefined ) { +/** +* Transforms flashVars object into a string for Url or Flashvars string. +* +* @method flashVarsToUrl +* @param {Object} flashVarsObject A flashvars object +* @param {String} paramName The name parameter to add to url +* @return {String} Returns flashVars string like: &foo=bar or ¶m[foo]=bar +*/ +var flashVarsToUrl = function( flashVarsObject, paramName ) { + var params = ''; + + var paramPrefix = (paramName) ? paramName + '[' : ''; + var paramSuffix = (paramName) ? ']' : ''; + + for( var i in flashVarsObject ){ + // check for object representation of plugin config: + if( typeof flashVarsObject[i] == 'object' ){ + for( var j in flashVarsObject[i] ){ + params+= '&' + paramPrefix + encodeURIComponent( i ) + + '.' + encodeURIComponent( j ) + paramSuffix + + '=' + encodeURIComponent( flashVarsObject[i][j] ); + } + } else { + params+= '&' + paramPrefix + encodeURIComponent( i ) + paramSuffix + '=' + encodeURIComponent( flashVarsObject[i] ); + } + } + return params; +}; + +// Setup handlebars helpers +Handlebars.registerHelper('flashVarsUrl', function(flashVars) { + return flashVarsToUrl(flashVars, 'flashvars'); +}); +Handlebars.registerHelper('flashVarsString', function(flashVars) { + return flashVarsToUrl(flashVars); +}); +Handlebars.registerHelper('elAttributes', function( attributes ) { + var str = ''; + for( var i in attributes ) { + str += ' ' + i + '="' + attributes[i] + '"'; + } + return str; +}); +// Include kaltura links +Handlebars.registerHelper('kalturaLinks', function() { + if( ! this.includeKalturaLinks ) { + return ''; + } + var template = Handlebars.templates['kaltura_links']; + return template(); +}); + +Handlebars.registerHelper('seoMetadata', function() { + var template = Handlebars.templates['seo_metadata']; + return template(this); +}); + +})(this, this.Handlebars); +(function(){var a=Handlebars.template,b=Handlebars.templates=Handlebars.templates||{};b.auto=a(function(a,b,c,d,e){function p(a,b){var d="",e,f;d+='
",i=c.seoMetadata,e=i||a.seoMetadata,typeof e===l?e=e.call(a,{hash:{}}):e===n&&(e=m.call(a,"seoMetadata",{hash:{}}));if(e||e===0)d+=e;i=c.kalturaLinks,e=i||a.kalturaLinks,typeof e===l?e=e.call(a,{hash:{}}):e===n&&(e=m.call(a,"kalturaLinks",{hash:{}}));if(e||e===0)d+=e;return d+="
\n",d}function q(a,b){var d="",e;return d+="&entry_id=",i=c.entryId,e=i||a.entryId,typeof e===l?e=e.call(a,{hash:{}}):e===n&&(e=m.call(a,"entryId",{hash:{}})),d+=o(e),d}function r(a,b){var d="",e;return d+="&cache_st=",i=c.cacheSt,e=i||a.cacheSt,typeof e===l?e=e.call(a,{hash:{}}):e===n&&(e=m.call(a,"cacheSt",{hash:{}})),d+=o(e),d}c=c||a.helpers;var f="",g,h,i,j,k=this,l="function",m=c.helperMissing,n=void 0,o=this.escapeExpression;i=c.includeSeoMetadata,g=i||b.includeSeoMetadata,h=c["if"],j=k.program(1,p,e),j.hash={},j.fn=j,j.inverse=k.noop,g=h.call(b,g,j);if(g||g===0)f+=g;f+='\n
",i=c.seoMetadata,g=i||b.seoMetadata,typeof g===k?g=g.call(b,{hash:{}}):g===m&&(g=l.call(b,"seoMetadata",{hash:{}}));if(g||g===0)f+=g;i=c.kalturaLinks,g=i||b.kalturaLinks,typeof g===k?g=g.call(b,{hash:{}}):g===m&&(g=l.call(b,"kalturaLinks",{hash:{}}));if(g||g===0)f+=g;f+="
\n",f}),b.iframe=a(function(a,b,c,d,e){function p(a,b){var d="",e;return d+="&entry_id=",i=c.entryId,e=i||a.entryId,typeof e===l?e=e.call(a,{hash:{}}):e===n&&(e=m.call(a,"entryId",{hash:{}})),d+=o(e),d}c=c||a.helpers;var f="",g,h,i,j,k=this,l="function",m=c.helperMissing,n=void 0,o=this.escapeExpression;f+='",f}),b.kaltura_links=a(function(a,b,c,d,e){c=c||a.helpers;var f,g=this;return'Video Platform\nVideo Management \nVideo Solutions\nVideo Player'}),b.legacy=a(function(a,b,c,d,e){function p(a,b){var d="",e;return d+='\n',d}function q(a,b){var d="",e;return d+='\n \n \n \n \n \n \n ',d}c=c||a.helpers;var f="",g,h,i,j,k=this,l="function",m=c.helperMissing,n=void 0,o=this.escapeExpression;i=c.includeHtml5Library,g=i||b.includeHtml5Library,h=c["if"],j=k.program(1,p,e),j.hash={},j.fn=j,j.inverse=k.noop,g=h.call(b,g,j);if(g||g===0)f+=g;f+='\n \n \n \n \n \n \n ',i=c.includeSeoMetadata,g=i||b.includeSeoMetadata,h=c["if"],j=k.program(3,q,e),j.hash={},j.fn=j,j.inverse=k.noop,g=h.call(b,g,j);if(g||g===0)f+=g;i=c.kalturaLinks,g=i||b.kalturaLinks,typeof g===l?g=g.call(b,{hash:{}}):g===n&&(g=m.call(b,"kalturaLinks",{hash:{}}));if(g||g===0)f+=g;return f+="\n",f}),b.seo_metadata=a(function(a,b,c,d,e){function o(a,b){var d="",e;return d+='\n\n\n\n\n\n\n',d}c=c||a.helpers;var f,g,h,i,j=this,k="function",l=c.helperMissing,m=void 0,n=this.escapeExpression;return h=c.includeSeoMetadata,f=h||b.includeSeoMetadata,g=c["if"],i=j.program(1,o,e),i.hash={},i.fn=i,i.inverse=j.noop,f=g.call(b,f,i),f||f===0?f:""})})() +// Add indexOf to array object +if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { + "use strict"; + if (this == null) { + throw new TypeError(); + } + var t = Object(this); + var len = t.length >>> 0; + if (len === 0) { + return -1; + } + var n = 0; + if (arguments.length > 1) { + n = Number(arguments[1]); + if (n !== n) { // shortcut for verifying if it's NaN + n = 0; + } else if (n !== 0 && n !== Infinity && n !== -Infinity) { + n = (n > 0 || -1) * Math.floor(Math.abs(n)); + } + } + if (n >= len) { + return -1; + } + var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); + for (; k < len; k++) { + if (k in t && t[k] === searchElement) { + return k; + } + } + return -1; + }; +} +// Add keys for Object +if (!Object.keys) { + Object.keys = (function () { + var hasOwnProperty = Object.prototype.hasOwnProperty, + hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), + dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ], + dontEnumsLength = dontEnums.length; + + return function (obj) { + if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) { + throw new TypeError('Object.keys called on non-object'); + } + + var result = []; + + for (var prop in obj) { + if (hasOwnProperty.call(obj, prop)) { + result.push(prop); + } + } + + if (hasDontEnumBug) { + for (var i=0; i < dontEnumsLength; i++) { + if (hasOwnProperty.call(obj, dontEnums[i])) { + result.push(dontEnums[i]); + } + } + } + return result; + }; + })(); +} +(function( window, undefined ) { +/** +* Kaltura Embed Code Generator +* Used to generate different type of embed codes +* Depended on Handlebars ( http://handlebarsjs.com/ ) +* +* @class EmbedCodeGenerator +* @constructor +*/ +var EmbedCodeGenerator = function( options ) { + this.init( options ); +}; + +EmbedCodeGenerator.prototype = { + + types: ['auto', 'dynamic', 'thumb', 'iframe', 'legacy'], + required: ['widgetId', 'partnerId', 'uiConfId'], + + defaults: { + /** + * Embed code type to generate + * Can we one of: ['auto', 'dynamic', 'thumb', 'iframe', 'legacy'] + * + * @property embedType + * @type {String} + * @default "auto" + */ + embedType: 'auto', + /** + * The Player element Id / Name that will be used for embed code + * + * @property playerId + * @type {String} + * @default "kaltura_player" + */ + playerId: 'kaltura_player', + /** + * Embed HTTP protocol to use + * Can we one of: ['http', 'https'] + * + * @property protocol + * @type {String} + * @default "http" + */ + protocol: 'http', + /** + * Host for loading html5 library & kdp swf + * + * @property host + * @type {String} + * @default "www.kaltura.com" + */ + host: 'www.kaltura.com', + /** + * Secured host for loading html5 library & kdp swf + * Used if protocol is: 'https' + * + * @property securedHost + * @type {String} + * @default "www.kaltura.com" + */ + securedHost: 'www.kaltura.com', + /** + * Kaltura Widget Id + * + * @property widgetId + * @type {String} + * @default "_{partnerId}" + */ + widgetId: null, + /** + * Kaltura Partner Id + * + * @property partnerId + * @type {Number} + * @default null, + */ + partnerId: null, + /** + * Add cacheSt parameter to bust cache + * Should be unix timestamp of future time + * + * @property cacheSt + * @type {Number} + * @default null, + */ + cacheSt: null, + /** + * Kaltura UiConf Id + * + * @property uiConfId + * @type {Number} + * @default null, + */ + uiConfId: null, + /** + * Kaltura Entry Id + * + * @property entryId + * @type {String} + * @default null, + */ + entryId: null, + /** + * Entry Object similar to: + * { + * name: 'Foo', + * description: 'Bar', + * thumbUrl: 'http://cdnbakmi.kaltura.com/thumbnail/...' + * } + * + * @property entryMeta + * @type {Object} + * @default {}, + */ + entryMeta: {}, + /** + * Sets Player Width + * + * @property width + * @type {Number} + * @default 400, + */ + width: 400, + /** + * Sets Player Height + * + * @property height + * @type {Number} + * @default 330, + */ + height: 330, + /** + * Adds additonal attributes to embed code. + * Example: + * { + * "class": "player" + * } + * + * @property attributes + * @type {Object} + * @default {}, + */ + attributes: {}, + /** + * Adds flashVars to player + * Example: + * { + * "autoPlay": "true" + * } + * + * @property flashVars + * @type {Object} + * @default {}, + */ + flashVars: {}, + /** + * Include Kaltura SEO links to embed code + * + * @property includeKalturaLinks + * @type {Boolean} + * @default true, + */ + includeKalturaLinks: true, + /** + * Include Entry Seo Metadata + * Metadata is taken from {entryMeta} object + * + * @property includeSeoMetadata + * @type {Boolean} + * @default false, + */ + includeSeoMetadata: false, + /** + * Include HTML5 library script + * + * @property includeHtml5Library + * @type {Boolean} + * @default true, + */ + includeHtml5Library: true + }, + /** + * Merge two object together + * + * @method extend + * @param {Object} destination object to merge into + * @param {Object} sourece object to merge from + * @return {Object} Merged object + */ + extend: function(destination, source) { + for (var property in source) { + if (source.hasOwnProperty(property) && !destination.hasOwnProperty(property)) { + destination[property] = source[property]; + } + } + return destination; + }, + /** + * Check if property is null + * + * @method isNull + * @param {Any} property some var + * @return {Boolean} + */ + isNull: function( property ) { + if (property.length && property.length > 0) { + return false; + } + if (property.length && property.length === 0) { + return true; + } + if( typeof property === 'object' ) { + return (Object.keys(property).length > 0) ? false : true; + } + return !property; + }, + /** + * Set default options to EmbedCodeGenerator instance + * + * @method init + * @param {Object} options Configuration object based on defaults object + * @return {Object} Returns the current instance + */ + init: function( options ) { + + options = options || {}; + + var defaults = this.defaults; + + // Make sure Handlebars is available + if( typeof Handlebars === undefined ) { + throw 'Handlebars is not defined, please include Handlebars.js before this script'; + } + + // Merge options with defaults + if( typeof options === 'object' ) { + this.options = this.extend(options, this.defaults); + } + // Set widgetId to partnerId if not defined + if( ! this.config('widgetId') && this.config('partnerId') ) { + this.config('widgetId', '_' + this.config('partnerId')); + } + + return this; + }, + /** + * Get or Set default configuration + * + * @method config + * @param {String} key configuration property name + * @param {Any} value to set + * @return {Mixed} Return the value for the key, configuration object or null + */ + config: function( key, val ) { + // Used as getter + if( val === undefined && typeof key === 'string' && this.options.hasOwnProperty(key) ) { + return this.options[ key ]; + } + // Get all options + if( key === undefined && val === undefined ) { + return this.options; + } + // Used as setter + if( typeof key === 'string' && val !== undefined ) { + this.options[ key ] = val; + } + return null; + }, + /** + * Check if required parameters are missing + * + * @method checkRequiredParams + * @param {Object} Configuration object + * @return throws exception if missing parameters + */ + checkRequiredParams: function( params ) { + var requiredLength = this.required.length, + i = 0; + // Check for required configuration + for(i; i') - .css("width", options.width+"px") - .css("height", options.height+"px") - .css("border", "0px") - .css("border-collapse", "collapse") - .css('background-color', options.background); - - // compute tileS percentage - var tileW = options.width / qrcode.getModuleCount(); - var tileH = options.height / qrcode.getModuleCount(); - - // draw in the table - for(var row = 0; row < qrcode.getModuleCount(); row++ ){ - var $row = $('').css('height', tileH+"px").appendTo($table); - - for(var col = 0; col < qrcode.getModuleCount(); col++ ){ - $('') - .css('width', tileW+"px") - .css('background-color', qrcode.isDark(row, col) ? options.foreground : options.background) - .appendTo($row); - } - } - // return just built canvas - return $table; - } - - - return this.each(function(){ - var element = options.render == "canvas" ? createCanvas() : createTable(); - $(element).appendTo(this); - }); - }; -})( jQuery ); - -// jQuery.XDomainRequest.js -// Author: Jason Moon - @JSONMOON -// IE8+ -if ( window.XDomainRequest ) { - jQuery.ajaxTransport(function( s ) { - if ( s.crossDomain && s.async ) { - if ( s.timeout ) { - s.xdrTimeout = s.timeout; - delete s.timeout; - } - var xdr; - return { - send: function( _, complete ) { - function callback( status, statusText, responses, responseHeaders ) { - xdr.onload = xdr.onerror = xdr.ontimeout = jQuery.noop; - xdr = undefined; - complete( status, statusText, responses, responseHeaders ); - } - xdr = new XDomainRequest(); - xdr.onload = function() { - callback( 200, "OK", { text: xdr.responseText }, "Content-Type: " + xdr.contentType ); - }; - xdr.onerror = function() { - callback( 404, "Not Found" ); - }; - xdr.onprogress = jQuery.noop; - xdr.ontimeout = function() { - callback( 0, "timeout" ); - }; - xdr.timeout = s.xdrTimeout || Number.MAX_VALUE; - xdr.open( s.type, s.url ); - xdr.send( ( s.hasContent && s.data ) || null ); - }, - abort: function() { - if ( xdr ) { - xdr.onerror = jQuery.noop; - xdr.abort(); - } - } - }; - } - }); -} -/*! - * zeroclipboard - * The Zero Clipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie, and a JavaScript interface. - * Copyright 2012 Jon Rohan, James M. Greene, . - * Released under the MIT license - * http://jonrohan.github.com/ZeroClipboard/ - * v1.1.7 - */(function() { - "use strict"; - var _getStyle = function(el, prop) { - var y = el.style[prop]; - if (el.currentStyle) y = el.currentStyle[prop]; else if (window.getComputedStyle) y = document.defaultView.getComputedStyle(el, null).getPropertyValue(prop); - if (y == "auto" && prop == "cursor") { - var possiblePointers = [ "a" ]; - for (var i = 0; i < possiblePointers.length; i++) { - if (el.tagName.toLowerCase() == possiblePointers[i]) { - return "pointer"; - } - } - } - return y; - }; - var _elementMouseOver = function(event) { - if (!ZeroClipboard.prototype._singleton) return; - if (!event) { - event = window.event; - } - var target; - if (this !== window) { - target = this; - } else if (event.target) { - target = event.target; - } else if (event.srcElement) { - target = event.srcElement; - } - ZeroClipboard.prototype._singleton.setCurrent(target); - }; - var _addEventHandler = function(element, method, func) { - if (element.addEventListener) { - element.addEventListener(method, func, false); - } else if (element.attachEvent) { - element.attachEvent("on" + method, func); - } - }; - var _removeEventHandler = function(element, method, func) { - if (element.removeEventListener) { - element.removeEventListener(method, func, false); - } else if (element.detachEvent) { - element.detachEvent("on" + method, func); - } - }; - var _addClass = function(element, value) { - if (element.addClass) { - element.addClass(value); - return element; - } - if (value && typeof value === "string") { - var classNames = (value || "").split(/\s+/); - if (element.nodeType === 1) { - if (!element.className) { - element.className = value; - } else { - var className = " " + element.className + " ", setClass = element.className; - for (var c = 0, cl = classNames.length; c < cl; c++) { - if (className.indexOf(" " + classNames[c] + " ") < 0) { - setClass += " " + classNames[c]; - } - } - element.className = setClass.replace(/^\s+|\s+$/g, ""); - } - } - } - return element; - }; - var _removeClass = function(element, value) { - if (element.removeClass) { - element.removeClass(value); - return element; - } - if (value && typeof value === "string" || value === undefined) { - var classNames = (value || "").split(/\s+/); - if (element.nodeType === 1 && element.className) { - if (value) { - var className = (" " + element.className + " ").replace(/[\n\t]/g, " "); - for (var c = 0, cl = classNames.length; c < cl; c++) { - className = className.replace(" " + classNames[c] + " ", " "); - } - element.className = className.replace(/^\s+|\s+$/g, ""); - } else { - element.className = ""; - } - } - } - return element; - }; - var _getDOMObjectPosition = function(obj) { - var info = { - left: 0, - top: 0, - width: obj.width || obj.offsetWidth || 0, - height: obj.height || obj.offsetHeight || 0, - zIndex: 9999 - }; - var zi = _getStyle(obj, "zIndex"); - if (zi && zi != "auto") { - info.zIndex = parseInt(zi, 10); - } - while (obj) { - var borderLeftWidth = parseInt(_getStyle(obj, "borderLeftWidth"), 10); - var borderTopWidth = parseInt(_getStyle(obj, "borderTopWidth"), 10); - info.left += isNaN(obj.offsetLeft) ? 0 : obj.offsetLeft; - info.left += isNaN(borderLeftWidth) ? 0 : borderLeftWidth; - info.top += isNaN(obj.offsetTop) ? 0 : obj.offsetTop; - info.top += isNaN(borderTopWidth) ? 0 : borderTopWidth; - obj = obj.offsetParent; - } - return info; - }; - var _noCache = function(path) { - return (path.indexOf("?") >= 0 ? "&" : "?") + "nocache=" + (new Date).getTime(); - }; - var _vars = function(options) { - var str = []; - if (options.trustedDomains) { - if (typeof options.trustedDomains === "string") { - str.push("trustedDomain=" + options.trustedDomains); - } else { - str.push("trustedDomain=" + options.trustedDomains.join(",")); - } - } - return str.join("&"); - }; - var _inArray = function(elem, array) { - if (array.indexOf) { - return array.indexOf(elem); - } - for (var i = 0, length = array.length; i < length; i++) { - if (array[i] === elem) { - return i; - } - } - return -1; - }; - var _prepGlue = function(elements) { - if (typeof elements === "string") throw new TypeError("ZeroClipboard doesn't accept query strings."); - if (!elements.length) return [ elements ]; - return elements; - }; - var ZeroClipboard = function(elements, options) { - if (elements) (ZeroClipboard.prototype._singleton || this).glue(elements); - if (ZeroClipboard.prototype._singleton) return ZeroClipboard.prototype._singleton; - ZeroClipboard.prototype._singleton = this; - this.options = {}; - for (var kd in _defaults) this.options[kd] = _defaults[kd]; - for (var ko in options) this.options[ko] = options[ko]; - this.handlers = {}; - if (ZeroClipboard.detectFlashSupport()) _bridge(); - }; - var currentElement, gluedElements = []; - ZeroClipboard.prototype.setCurrent = function(element) { - currentElement = element; - this.reposition(); - if (element.getAttribute("title")) { - this.setTitle(element.getAttribute("title")); - } - this.setHandCursor(_getStyle(element, "cursor") == "pointer"); - }; - ZeroClipboard.prototype.setText = function(newText) { - if (newText && newText !== "") { - this.options.text = newText; - if (this.ready()) this.flashBridge.setText(newText); - } - }; - ZeroClipboard.prototype.setTitle = function(newTitle) { - if (newTitle && newTitle !== "") this.htmlBridge.setAttribute("title", newTitle); - }; - ZeroClipboard.prototype.setSize = function(width, height) { - if (this.ready()) this.flashBridge.setSize(width, height); - }; - ZeroClipboard.prototype.setHandCursor = function(enabled) { - if (this.ready()) this.flashBridge.setHandCursor(enabled); - }; - ZeroClipboard.version = "1.1.7"; - var _defaults = { - moviePath: "ZeroClipboard.swf", - trustedDomains: null, - text: null, - hoverClass: "zeroclipboard-is-hover", - activeClass: "zeroclipboard-is-active", - allowScriptAccess: "sameDomain" - }; - ZeroClipboard.setDefaults = function(options) { - for (var ko in options) _defaults[ko] = options[ko]; - }; - ZeroClipboard.destroy = function() { - ZeroClipboard.prototype._singleton.unglue(gluedElements); - var bridge = ZeroClipboard.prototype._singleton.htmlBridge; - bridge.parentNode.removeChild(bridge); - delete ZeroClipboard.prototype._singleton; - }; - ZeroClipboard.detectFlashSupport = function() { - var hasFlash = false; - try { - if (new ActiveXObject("ShockwaveFlash.ShockwaveFlash")) { - hasFlash = true; - } - } catch (error) { - if (navigator.mimeTypes["application/x-shockwave-flash"]) { - hasFlash = true; - } - } - return hasFlash; - }; - var _bridge = function() { - var client = ZeroClipboard.prototype._singleton; - var container = document.getElementById("global-zeroclipboard-html-bridge"); - if (!container) { - var html = ' '; - container = document.createElement("div"); - container.id = "global-zeroclipboard-html-bridge"; - container.setAttribute("class", "global-zeroclipboard-container"); - container.setAttribute("data-clipboard-ready", false); - container.style.position = "absolute"; - container.style.left = "-9999px"; - container.style.top = "-9999px"; - container.style.width = "15px"; - container.style.height = "15px"; - container.style.zIndex = "9999"; - container.innerHTML = html; - document.body.appendChild(container); - } - client.htmlBridge = container; - client.flashBridge = document["global-zeroclipboard-flash-bridge"] || container.children[0].lastElementChild; - }; - ZeroClipboard.prototype.resetBridge = function() { - this.htmlBridge.style.left = "-9999px"; - this.htmlBridge.style.top = "-9999px"; - this.htmlBridge.removeAttribute("title"); - this.htmlBridge.removeAttribute("data-clipboard-text"); - _removeClass(currentElement, this.options.activeClass); - currentElement = null; - this.options.text = null; - }; - ZeroClipboard.prototype.ready = function() { - var ready = this.htmlBridge.getAttribute("data-clipboard-ready"); - return ready === "true" || ready === true; - }; - ZeroClipboard.prototype.reposition = function() { - if (!currentElement) return false; - var pos = _getDOMObjectPosition(currentElement); - var topOffset = $(currentElement).hasClass("pullright") ? $(".form-horizontal").scrollTop() : 0; - this.htmlBridge.style.top = pos.top - topOffset + "px"; - this.htmlBridge.style.left = pos.left + "px"; - this.htmlBridge.style.width = pos.width + "px"; - this.htmlBridge.style.height = pos.height + "px"; - this.htmlBridge.style.zIndex = pos.zIndex + 1; - this.setSize(pos.width, pos.height); - }; - ZeroClipboard.dispatch = function(eventName, args) { - ZeroClipboard.prototype._singleton.receiveEvent(eventName, args); - }; - ZeroClipboard.prototype.on = function(eventName, func) { - var events = eventName.toString().split(/\s/g); - for (var i = 0; i < events.length; i++) { - eventName = events[i].toLowerCase().replace(/^on/, ""); - if (!this.handlers[eventName]) this.handlers[eventName] = func; - } - if (this.handlers.noflash && !ZeroClipboard.detectFlashSupport()) { - this.receiveEvent("onNoFlash", null); - } - }; - ZeroClipboard.prototype.addEventListener = ZeroClipboard.prototype.on; - ZeroClipboard.prototype.off = function(eventName, func) { - var events = eventName.toString().split(/\s/g); - for (var i = 0; i < events.length; i++) { - eventName = events[i].toLowerCase().replace(/^on/, ""); - for (var event in this.handlers) { - if (event === eventName && this.handlers[event] === func) { - delete this.handlers[event]; - } - } - } - }; - ZeroClipboard.prototype.removeEventListener = ZeroClipboard.prototype.off; - ZeroClipboard.prototype.receiveEvent = function(eventName, args) { - eventName = eventName.toString().toLowerCase().replace(/^on/, ""); - var element = currentElement; - switch (eventName) { - case "load": - if (args && parseFloat(args.flashVersion.replace(",", ".").replace(/[^0-9\.]/gi, "")) < 10) { - this.receiveEvent("onWrongFlash", { - flashVersion: args.flashVersion - }); - return; - } - this.htmlBridge.setAttribute("data-clipboard-ready", true); - break; - case "mouseover": - _addClass(element, this.options.hoverClass); - break; - case "mouseout": - _removeClass(element, this.options.hoverClass); - this.resetBridge(); - break; - case "mousedown": - _addClass(element, this.options.activeClass); - break; - case "mouseup": - _removeClass(element, this.options.activeClass); - break; - case "datarequested": - var targetId = element.getAttribute("data-clipboard-target"), targetEl = !targetId ? null : document.getElementById(targetId); - if (targetEl) { - var textContent = targetEl.value || targetEl.textContent || targetEl.innerText; - if (textContent) this.setText(textContent); - } else { - var defaultText = element.getAttribute("data-clipboard-text"); - if (defaultText) this.setText(defaultText); - } - break; - case "complete": - this.options.text = null; - break; - } - if (this.handlers[eventName]) { - var func = this.handlers[eventName]; - if (typeof func == "function") { - func.call(element, this, args); - } else if (typeof func == "string") { - window[func].call(element, this, args); - } - } - }; - ZeroClipboard.prototype.glue = function(elements) { - elements = _prepGlue(elements); - for (var i = 0; i < elements.length; i++) { - if (_inArray(elements[i], gluedElements) == -1) { - gluedElements.push(elements[i]); - _addEventHandler(elements[i], "mouseover", _elementMouseOver); - } - } - }; - ZeroClipboard.prototype.unglue = function(elements) { - elements = _prepGlue(elements); - for (var i = 0; i < elements.length; i++) { - _removeEventHandler(elements[i], "mouseover", _elementMouseOver); - var arrayIndex = _inArray(elements[i], gluedElements); - if (arrayIndex != -1) gluedElements.splice(arrayIndex, 1); - } - }; - if (typeof module !== "undefined") { - module.exports = ZeroClipboard; - } else if (typeof define === "function" && define.amd) { - define(function() { - return ZeroClipboard; - }); - } else { - window.ZeroClipboard = ZeroClipboard; - } -})(); -(function(kmc) { - - /* - * TODO: - * Use ng-view for preview template - * Use filters for delivery - */ - - var Preview = kmc.Preview || {}; - - // Preview Partner Defaults - kmc.vars.previewDefaults = { - showAdvancedOptions: false, - includeKalturaLinks: (!kmc.vars.ignore_seo_links), - includeSeoMetadata: (!kmc.vars.ignore_entry_seo), - deliveryType: kmc.vars.default_delivery_type, - embedType: kmc.vars.default_embed_code_type, - secureEmbed: kmc.vars.embed_code_protocol_https - }; - - // Check for current protocol and update secureEmbed - if(window.location.protocol == 'https:') { - kmc.vars.previewDefaults.secureEmbed = true; - } - - Preview.storageName = 'previewDefaults'; - Preview.el = '#previewModal'; - Preview.iframeContainer = 'previewIframe'; - - // We use this flag to ignore all change evnets when we initilize the preview ( on page start up ) - // We will set that to false once Preview is opened. - Preview.ignoreChangeEvents = true; - - // Set generator - Preview.getGenerator = function() { - if(!this.generator) { - this.generator = new kEmbedCodeGenerator({ - host: kmc.vars.embed_host, - securedHost: kmc.vars.embed_host_https, - partnerId: kmc.vars.partner_id, - includeKalturaLinks: kmc.vars.previewDefaults.includeKalturaLinks - }); - } - return this.generator; - }; - - Preview.clipboard = new ZeroClipboard($('.copy-code'), { - moviePath: "/lib/flash/ZeroClipboard.swf", - trustedDomains: ['*'], - allowScriptAccess: "always" - }); - - Preview.clipboard.on('complete', function() { - var $this = $(this); - // Mark embed code as selected - $('#' + $this.data('clipboard-target')).select(); - // Close preview - if($this.data('close') === true) { - Preview.closeModal(Preview.el); - } - }); - - Preview.objectToArray = function(obj) { - var arr = []; - for(var key in obj) { - obj[key].id = key; - arr.push(obj[key]); - } - return arr; - }; - - Preview.getObjectById = function(id, arr) { - var result = $.grep(arr, function(e) { - return e.id == id; - }); - return(result.length) ? result[0] : false; - }; - - Preview.getDefault = function(setting) { - var defaults = localStorage.getItem(Preview.storageName); - if(defaults) { - defaults = JSON.parse(defaults); - } else { - defaults = kmc.vars.previewDefaults; - } - if(defaults[setting] !== undefined) { - return defaults[setting]; - } - return null; - }; - - Preview.savePreviewState = function() { - var previewService = this.Service; - var defaults = { - embedType: previewService.get('embedType'), - secureEmbed: previewService.get('secureEmbed'), - includeSeoMetadata: previewService.get('includeSeo'), - deliveryType: previewService.get('deliveryType').id, - showAdvancedOptions: previewService.get('showAdvancedOptions') - }; - // Save defaults to localStorage - localStorage.setItem(Preview.storageName, JSON.stringify(defaults)); - }; - - Preview.getDeliveryTypeFlashVars = function(deliveryType) { - // Not delivery type, exit - if(!deliveryType) return {}; - - // Get original delivery type flashvars - var originalFlashVars = (deliveryType.flashvars) ? deliveryType.flashvars : {}; - - // Clone flashVars object - var newFlashVars = $.extend({}, originalFlashVars); - - // Add streamerType and mediaProtocol flashVars - if(deliveryType.streamerType) - newFlashVars.streamerType = deliveryType.streamerType; - - if(deliveryType.mediaProtocol) - newFlashVars.mediaProtocol = deliveryType.mediaProtocol; - - // Return the new Flashvars object - return newFlashVars; - }; - - Preview.getPreviewTitle = function(options) { - if(options.entryMeta && options.entryMeta.name) { - return 'Embedding: ' + options.entryMeta.name; - } - if(options.playlistName) { - return 'Playlist: ' + options.playlistName; - } - if(options.playerOnly) { - return 'Player Name:' + options.name; - } - }; - - Preview.openPreviewEmbed = function(options, previewService) { - - var _this = this; - var el = _this.el; - - // Enable preview events - this.ignoreChangeEvents = false; - - var defaults = { - entryId: null, - entryMeta: {}, - playlistId: null, - playlistName: null, - previewOnly: null, - liveBitrates: null, - playerOnly: false, - uiConfId: null, - name: null - }; - - options = $.extend({}, defaults, options); - previewService.disableEvents(); - // In case of live entry preview, set delivery type to auto - if( options.liveBitrates ) { - previewService.set('live', true); - previewService.setDeliveryType('auto'); - }else{ - previewService.set('live',false); - } - // Update our players - previewService.updatePlayers(options); - previewService.enableEvents(); - // Set options - previewService.set(options); - - var title = this.getPreviewTitle(options); - - var $previewModal = $(el); - $previewModal.find(".title h2").text(title).attr('title', title); - $previewModal.find(".close").unbind('click').click(function() { - _this.closeModal(el); - }); - - // Show our preview modal - var modalHeight = $('body').height() - 173; - $previewModal.find('.content').height(modalHeight); - kmc.layout.modal.show(el, false); - }; - - Preview.closeModal = function(el) { - this.savePreviewState(); - this.emptyDiv(this.iframeContainer); - $(el).fadeOut(300, function() { - kmc.layout.overlay.hide(); - kmc.utils.hideFlash(); - }); - }; - - Preview.emptyDiv = function(divId) { - var $targetDiv = $('#' + divId); - var $previewIframe = $('#previewIframe iframe'); - if( $previewIframe.length ) { - try { - var $iframeDoc = $($previewIframe[0].contentWindow.document); - $iframeDoc.find('#framePlayerContainer').empty(); - } catch (e) {} - } - - if( $targetDiv.length ) { - $targetDiv.empty(); - return $targetDiv[0]; - } - return false; - }; - - Preview.hasIframe = function() { - return $('#' + this.iframeContainer + ' iframe').length; - }; - - Preview.getCacheSt = function() { - var d = new Date(); - return Math.floor(d.getTime() / 1000) + (15 * 60); // start caching in 15 minutes - }; - - Preview.generateIframe = function(embedCode) { - - var ltIE10 = $('html').hasClass('lt-ie10'); - var is_firefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; - var style = ''; - var container = this.emptyDiv(this.iframeContainer); - var iframe = document.createElement('iframe'); - // Reset iframe style - iframe.frameborder = "0"; - iframe.frameBorder = "0"; - iframe.marginheight="0"; - iframe.marginwidth="0"; - iframe.frameborder="0"; - iframe.setAttribute('allowFullScreen', ''); - iframe.setAttribute('webkitallowfullscreen', ''); - iframe.setAttribute('mozallowfullscreen', ''); - - container.appendChild(iframe); - - if(ltIE10 || is_firefox) { - iframe.src = this.getPreviewUrl(this.Service, true); - } else { - var newDoc = iframe.contentDocument; - newDoc.open(); - newDoc.write('' + style + '
' + embedCode + '
'); - newDoc.close(); - } - }; - - Preview.getEmbedProtocol = function(previewService, previewPlayer) { - if(previewPlayer === true) { - return location.protocol.substring(0, location.protocol.length - 1); // Get host protocol - } - return (previewService.get('secureEmbed')) ? 'https' : 'http'; - }; - - Preview.getEmbedFlashVars = function(previewService, previewPlayer) { - var protocol = this.getEmbedProtocol(previewService, previewPlayer); - var player = previewService.get('player'); - var flashVars = this.getDeliveryTypeFlashVars(previewService.get('deliveryType')); - if(previewPlayer === true) { - flashVars.ks = kmc.vars.ks; - if (previewService.get('live') == true){ - flashVars.disableEntryRedirect = true; - } - flashVars['liveAnalytics'] = { - "plugin": "false", // prevent loading the liveAnalytics plugin in v2 players - "relativeTo": "PlayerHolder", // required to prevent v1 players from getting stuck - "position": "after", // required to prevent v1 players from getting stuck - "loadingPolicy": "onDemand" // prevent v1 players from trying to load this plugin - }; - } - - var playlistId = previewService.get('playlistId'); - if(playlistId) { - // Use new kpl0Id flashvar for new players only - var html5_version = kmc.functions.getVersionFromPath(player.html5Url); - var kdpVersionCheck = kmc.functions.versionIsAtLeast(kmc.vars.min_kdp_version_for_playlist_api_v3, player.swf_version); - var html5VersionCheck = kmc.functions.versionIsAtLeast(kmc.vars.min_html5_version_for_playlist_api_v3, html5_version); - if( kdpVersionCheck && html5VersionCheck ) { - flashVars['playlistAPI.kpl0Id'] = playlistId; - } else { - flashVars['playlistAPI.autoInsert'] = 'true'; - flashVars['playlistAPI.kpl0Name'] = previewService.get('playlistName'); - flashVars['playlistAPI.kpl0Url'] = protocol + '://' + kmc.vars.api_host + '/index.php/partnerservices2/executeplaylist?' + 'partner_id=' + kmc.vars.partner_id + '&subp_id=' + kmc.vars.partner_id + '00' + '&format=8&ks={ks}&playlist_id=' + playlistId; - } - } - return flashVars; - }; - - Preview.getEmbedCode = function(previewService, previewPlayer) { - var player = previewService.get('player'); - if(!player || !previewService.get('embedType')) { - return ''; - } - var cacheSt = this.getCacheSt(); - var params = { - protocol: this.getEmbedProtocol(previewService, previewPlayer), - embedType: previewService.get('embedType'), - uiConfId: player.id, - width: player.width, - height: player.height, - entryMeta: previewService.get('entryMeta'), - includeSeoMetadata: previewService.get('includeSeo'), - playerId: 'kaltura_player_' + cacheSt, - cacheSt: cacheSt, - flashVars: this.getEmbedFlashVars(previewService, previewPlayer) - }; - - if(previewService.get('entryId')) { - params.entryId = previewService.get('entryId'); - } - - var code = this.getGenerator().getCode(params); - return code; - }; - - Preview.getPreviewUrl = function(previewService, framed) { - var player = previewService.get('player'); - if(!player || !previewService.get('embedType')) { - return ''; - } - - var protocol = this.getEmbedProtocol(previewService, framed); - var url = protocol + '://' + kmc.vars.api_host + '/index.php/extwidget/preview'; - //var url = protocol + '://' + window.location.host + '/KMC_V2/preview.php'; - url += '/partner_id/' + kmc.vars.partner_id; - url += '/uiconf_id/' + player.id; - // Add entry Id - if(previewService.get('entryId')) { - url += '/entry_id/' + previewService.get('entryId'); - } - url += '/embed/' + previewService.get('embedType'); - url += '?' + kmc.functions.flashVarsToUrl(this.getEmbedFlashVars(previewService, framed)); - if( framed === true ) { - url += '&framed=true'; - } - return url; - }; - - Preview.generateQrCode = function(url) { - var $qrCode = $('#qrcode').empty(); - if(!url) return ; - if($('html').hasClass('lt-ie9')) return; - $qrCode.qrcode({ - width: 80, - height: 80, - text: url - }); - }; - - Preview.generateShortUrl = function(url, callback) { - if(!url) return ; - kmc.client.createShortURL(url, callback); - }; - - kmc.Preview = Preview; - -})(window.kmc); - -var kmcApp = angular.module('kmcApp', ['pascalprecht.translate']); - -kmcApp.config(['$translateProvider', function ($translateProvider) { - $translateProvider.useStaticFilesLoader({ - prefix: '/locales/locale-', - suffix: '.json' - }); - - var lang = 'en'; - if (typeof localStorage != "unknown" && typeof localStorage["lang"] !== "undefined"){ - lang = localStorage["lang"]; - } - // take the first two characters - if( lang.length > 2 ){ - lang = lang.toLowerCase().substr(0,2); - } - $translateProvider.preferredLanguage(lang); -}]); - - -kmcApp.factory('previewService', ['$rootScope', function($rootScope) { - var previewProps = {}; - var disableCount = 0; - return { - get: function(key) { - if(key === undefined) return previewProps; - return previewProps[key]; - }, - set: function(key, value, quiet) { - if(typeof key == 'object') { - angular.extend(previewProps, key); - } else { - previewProps[key] = value; - } - if( !quiet && disableCount === 0 ) { - $rootScope.$broadcast('previewChanged'); - } - }, - enableEvents: function(){ - disableCount--; - }, - disableEvents: function(){ - disableCount++ - }, - updatePlayers: function(options) { - $rootScope.$broadcast('playersUpdated', options); - }, - changePlayer: function(playerId) { - $rootScope.$broadcast('changePlayer', playerId); - }, - setDeliveryType: function( deliveryTypeId ) { - $rootScope.$broadcast('changeDelivery', deliveryTypeId ); - } - }; -}]); -kmcApp.directive('showSlide', function() { - return { - //restrict it's use to attribute only. - restrict: 'A', - - //set up the directive. - link: function(scope, elem, attr) { - - //get the field to watch from the directive attribute. - var watchField = attr.showSlide; - - //set up the watch to toggle the element. - scope.$watch(attr.showSlide, function(v) { - if(v && !elem.is(':visible')) { - elem.slideDown(); - } else { - elem.slideUp(); - } - }); - } - }; -}); - -kmcApp.controller('PreviewCtrl', ['$scope', '$translate', 'previewService', function($scope, $translate, previewService) { - - var draw = function() { - if(!$scope.$$phase) { - $scope.$apply(); - } - }; + // set default values + // typeNumber < 1 for automatic calculation + options = $.extend( {}, { + render : "canvas", + width : 256, + height : 256, + typeNumber : -1, + correctLevel : QRErrorCorrectLevel.H, + background : "#ffffff", + foreground : "#000000" + }, options); - var Preview = kmc.Preview; - Preview.playlistMode = false; + var createCanvas = function(){ + // create the qrcode itself + var qrcode = new QRCode(options.typeNumber, options.correctLevel); + qrcode.addData(options.text); + qrcode.make(); - Preview.Service = previewService; + // create canvas element + var canvas = document.createElement('canvas'); + canvas.width = options.width; + canvas.height = options.height; + var ctx = canvas.getContext('2d'); - var updatePlayers = function(options) { - options = options || {}; - var playerId = (options.uiConfId) ? options.uiConfId : undefined; - // Exit if player not loaded - if(!kmc.vars.playlists_list && !kmc.vars.players_list) { - return ; - } - // List of players - if(options.playlistId || options.playerOnly) { - $scope.players = kmc.vars.playlists_list; - if(!Preview.playlistMode) { - Preview.playlistMode = true; - $scope.$broadcast('changePlayer', playerId); - return; - } - } else { - $scope.players = kmc.vars.players_list; - if(Preview.playlistMode || !$scope.player) { - Preview.playlistMode = false; - $scope.$broadcast('changePlayer', playerId); - return; - } - } - if(playerId){ - $scope.$broadcast('changePlayer', playerId); - } - }; + // compute tileW/tileH based on options.width/options.height + var tileW = options.width / qrcode.getModuleCount(); + var tileH = options.height / qrcode.getModuleCount(); - var setDeliveryTypes = function(player) { - //if( $scope.liveBitrates && $scope.liveBitrates != false ) { - previewService.setDeliveryType('auto'); - //} - var deliveryTypes = Preview.objectToArray(kmc.vars.delivery_types); - var defaultType = $scope.deliveryType || Preview.getDefault('deliveryType'); - var validDeliveryTypes = []; - $.each(deliveryTypes, function() { - if(this.minVersion && !kmc.functions.versionIsAtLeast(this.minVersion, player.swf_version)) { - if(this.id == defaultType) { - defaultType = null; - } - return true; - } - validDeliveryTypes.push(this); - }); - // List of delivery types - $scope.deliveryTypes = validDeliveryTypes; - // Set default delivery type - if(!defaultType) { - defaultType = $scope.deliveryTypes[0].id; + // draw in the canvas + for( var row = 0; row < qrcode.getModuleCount(); row++ ){ + for( var col = 0; col < qrcode.getModuleCount(); col++ ){ + ctx.fillStyle = qrcode.isDark(row, col) ? options.foreground : options.background; + var w = (Math.ceil((col+1)*tileW) - Math.floor(col*tileW)); + var h = (Math.ceil((row+1)*tileW) - Math.floor(row*tileW)); + ctx.fillRect(Math.round(col*tileW),Math.round(row*tileH), w, h); + } } - previewService.setDeliveryType(defaultType); - }; + // return just built canvas + return canvas; + } - var setEmbedTypes = function(player) { - var embedTypes = Preview.objectToArray(kmc.vars.embed_code_types); - var defaultType = $scope.embedType || Preview.getDefault('embedType'); - var validEmbedTypes = []; - $.each(embedTypes, function() { - // Don't add embed code that are entry only for playlists - if(Preview.playlistMode && this.entryOnly) { - if(this.id == defaultType) { - defaultType = null; - } - return true; - } + // from Jon-Carlos Rivera (https://github.com/imbcmdth) + var createTable = function(){ + // create the qrcode itself + var qrcode = new QRCode(options.typeNumber, options.correctLevel); + qrcode.addData(options.text); + qrcode.make(); + + // create table element + var $table = $('
') + .css("width", options.width+"px") + .css("height", options.height+"px") + .css("border", "0px") + .css("border-collapse", "collapse") + .css('background-color', options.background); + + // compute tileS percentage + var tileW = options.width / qrcode.getModuleCount(); + var tileH = options.height / qrcode.getModuleCount(); - // Check for library minimum version to eanble embed type. remove legacy embed for version 2 and up players - var libVersion = kmc.functions.getVersionFromPath(player.html5Url); - if((this.minVersion && !kmc.functions.versionIsAtLeast(this.minVersion, libVersion)) || - ((libVersion == "latest" || libVersion[0] == "2") && this.id == "legacy")) { - if(this.id == defaultType) { - defaultType = null; - } - return true; - } - validEmbedTypes.push(this); - }); - // List of embed types - $scope.embedTypes = validEmbedTypes; - // Set default embed type - if(!defaultType) { - defaultType = $scope.embedTypes[0].id; + // draw in the table + for(var row = 0; row < qrcode.getModuleCount(); row++ ){ + var $row = $('').css('height', tileH+"px").appendTo($table); + + for(var col = 0; col < qrcode.getModuleCount(); col++ ){ + $('') + .css('width', tileW+"px") + .css('background-color', qrcode.isDark(row, col) ? options.foreground : options.background) + .appendTo($row); + } } - $scope.embedType = defaultType; - }; - - // Set defaults - $scope.players = []; - $scope.player = null; - $scope.deliveryTypes = []; - $scope.deliveryType = null; - $scope.embedTypes = []; - $scope.embedType = null; - $scope.secureEmbed = Preview.getDefault('secureEmbed'); - $scope.includeSeo = Preview.getDefault('includeSeoMetadata'); - $scope.previewOnly = null; - $scope.playerOnly = false; - $scope.liveBitrates = false; - $scope.showAdvancedOptionsStatus = Preview.getDefault('showAdvancedOptions'); - $scope.shortLinkGenerated = false; - - // Set players on update - $scope.$on('playersUpdated', function(e, options) { - updatePlayers(options); - }); - - $scope.$on('changePlayer', function(e, playerId) { - if ( playerId || ( playerId === undefined && $scope.players && $scope.players.length )){ - playerId = ( playerId ) ? playerId : $scope.players[0].id; - $scope.player = playerId; - draw(); + // return just built canvas + return $table; } - }); - - $scope.$on('changeDelivery', function(e, deliveryTypeId) { - $scope.deliveryType = deliveryTypeId; - draw(); - }); - - $scope.showAdvancedOptions = function($event, show) { - $event.preventDefault(); - previewService.set('showAdvancedOptions', show, true); - $scope.showAdvancedOptionsStatus = show; - }; - - $scope.$watch('showAdvancedOptionsStatus', function() { - Preview.clipboard.reposition(); - }); + - // Listen to player change - $scope.$watch('player', function() { - var player = Preview.getObjectById($scope.player, $scope.players); - if(!player) { return ; } - previewService.disableEvents(); - setDeliveryTypes(player); - setEmbedTypes(player); - setTimeout(function(){ - previewService.enableEvents(); - previewService.set('player', player); - },0); - }); - $scope.$watch('deliveryType', function() { - var deliveryType = Preview.getObjectById($scope.deliveryType, $scope.deliveryTypes); - previewService.set('deliveryType', deliveryType); - if ( deliveryType.id === "hds" ){ - $scope.secureEmbed = false; - } - }); - $scope.$watch('embedType', function() { - previewService.set('embedType', $scope.embedType); - }); - $scope.$watch('secureEmbed', function() { - previewService.set('secureEmbed', $scope.secureEmbed); - }); - $scope.$watch('includeSeo', function() { - previewService.set('includeSeo', $scope.includeSeo); - }); - $scope.$watch('embedCodePreview', function() { - Preview.generateIframe($scope.embedCodePreview); - }); - $scope.$watch('previewOnly', function() { - if($scope.previewOnly) { - $scope.closeButtonText = $translate('CLOSE'); - } else { - $scope.closeButtonText = $translate('COPY_AND_CLOSE'); - } - draw(); - }); - $scope.$on('previewChanged', function() { - if(Preview.ignoreChangeEvents) return; - var previewUrl = Preview.getPreviewUrl(previewService); - $scope.embedCode = Preview.getEmbedCode(previewService); - $scope.embedCodePreview = Preview.getEmbedCode(previewService, true); - $scope.previewOnly = previewService.get('previewOnly'); - $scope.playerOnly = previewService.get('playerOnly'); - $scope.liveBitrates = previewService.get('liveBitrates'); - draw(); - // Generate Iframe if not exist - if(!Preview.hasIframe()) { - Preview.generateIframe($scope.embedCodePreview); - } - // Update Short url - $scope.previewUrl = $translate('UPDATING'); - $scope.shortLinkGenerated = false; - Preview.generateShortUrl(previewUrl, function(tinyUrl) { - if(!tinyUrl) { - // Set tinyUrl to fullUrl - tinyUrl = previewUrl; - } - $scope.shortLinkGenerated = true; - $scope.previewUrl = tinyUrl; - // Generate QR Code - Preview.generateQrCode(tinyUrl); - draw(); + return this.each(function(){ + var element = options.render == "canvas" ? createCanvas() : createTable(); + $(element).appendTo(this); }); - }); - -}]); + }; +})( jQuery ); + +// jQuery.XDomainRequest.js +// Author: Jason Moon - @JSONMOON +// IE8+ +if ( window.XDomainRequest ) { + jQuery.ajaxTransport(function( s ) { + if ( s.crossDomain && s.async ) { + if ( s.timeout ) { + s.xdrTimeout = s.timeout; + delete s.timeout; + } + var xdr; + return { + send: function( _, complete ) { + function callback( status, statusText, responses, responseHeaders ) { + xdr.onload = xdr.onerror = xdr.ontimeout = jQuery.noop; + xdr = undefined; + complete( status, statusText, responses, responseHeaders ); + } + xdr = new XDomainRequest(); + xdr.onload = function() { + callback( 200, "OK", { text: xdr.responseText }, "Content-Type: " + xdr.contentType ); + }; + xdr.onerror = function() { + callback( 404, "Not Found" ); + }; + xdr.onprogress = jQuery.noop; + xdr.ontimeout = function() { + callback( 0, "timeout" ); + }; + xdr.timeout = s.xdrTimeout || Number.MAX_VALUE; + xdr.open( s.type, s.url ); + xdr.send( ( s.hasContent && s.data ) || null ); + }, + abort: function() { + if ( xdr ) { + xdr.onerror = jQuery.noop; + xdr.abort(); + } + } + }; + } + }); +} +/*! + * zeroclipboard + * The Zero Clipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie, and a JavaScript interface. + * Copyright 2012 Jon Rohan, James M. Greene, . + * Released under the MIT license + * http://jonrohan.github.com/ZeroClipboard/ + * v1.1.7 + */(function() { + "use strict"; + var _getStyle = function(el, prop) { + var y = el.style[prop]; + if (el.currentStyle) y = el.currentStyle[prop]; else if (window.getComputedStyle) y = document.defaultView.getComputedStyle(el, null).getPropertyValue(prop); + if (y == "auto" && prop == "cursor") { + var possiblePointers = [ "a" ]; + for (var i = 0; i < possiblePointers.length; i++) { + if (el.tagName.toLowerCase() == possiblePointers[i]) { + return "pointer"; + } + } + } + return y; + }; + var _elementMouseOver = function(event) { + if (!ZeroClipboard.prototype._singleton) return; + if (!event) { + event = window.event; + } + var target; + if (this !== window) { + target = this; + } else if (event.target) { + target = event.target; + } else if (event.srcElement) { + target = event.srcElement; + } + ZeroClipboard.prototype._singleton.setCurrent(target); + }; + var _addEventHandler = function(element, method, func) { + if (element.addEventListener) { + element.addEventListener(method, func, false); + } else if (element.attachEvent) { + element.attachEvent("on" + method, func); + } + }; + var _removeEventHandler = function(element, method, func) { + if (element.removeEventListener) { + element.removeEventListener(method, func, false); + } else if (element.detachEvent) { + element.detachEvent("on" + method, func); + } + }; + var _addClass = function(element, value) { + if (element.addClass) { + element.addClass(value); + return element; + } + if (value && typeof value === "string") { + var classNames = (value || "").split(/\s+/); + if (element.nodeType === 1) { + if (!element.className) { + element.className = value; + } else { + var className = " " + element.className + " ", setClass = element.className; + for (var c = 0, cl = classNames.length; c < cl; c++) { + if (className.indexOf(" " + classNames[c] + " ") < 0) { + setClass += " " + classNames[c]; + } + } + element.className = setClass.replace(/^\s+|\s+$/g, ""); + } + } + } + return element; + }; + var _removeClass = function(element, value) { + if (element.removeClass) { + element.removeClass(value); + return element; + } + if (value && typeof value === "string" || value === undefined) { + var classNames = (value || "").split(/\s+/); + if (element.nodeType === 1 && element.className) { + if (value) { + var className = (" " + element.className + " ").replace(/[\n\t]/g, " "); + for (var c = 0, cl = classNames.length; c < cl; c++) { + className = className.replace(" " + classNames[c] + " ", " "); + } + element.className = className.replace(/^\s+|\s+$/g, ""); + } else { + element.className = ""; + } + } + } + return element; + }; + var _getDOMObjectPosition = function(obj) { + var info = { + left: 0, + top: 0, + width: obj.width || obj.offsetWidth || 0, + height: obj.height || obj.offsetHeight || 0, + zIndex: 9999 + }; + var zi = _getStyle(obj, "zIndex"); + if (zi && zi != "auto") { + info.zIndex = parseInt(zi, 10); + } + while (obj) { + var borderLeftWidth = parseInt(_getStyle(obj, "borderLeftWidth"), 10); + var borderTopWidth = parseInt(_getStyle(obj, "borderTopWidth"), 10); + info.left += isNaN(obj.offsetLeft) ? 0 : obj.offsetLeft; + info.left += isNaN(borderLeftWidth) ? 0 : borderLeftWidth; + info.top += isNaN(obj.offsetTop) ? 0 : obj.offsetTop; + info.top += isNaN(borderTopWidth) ? 0 : borderTopWidth; + obj = obj.offsetParent; + } + return info; + }; + var _noCache = function(path) { + return (path.indexOf("?") >= 0 ? "&" : "?") + "nocache=" + (new Date).getTime(); + }; + var _vars = function(options) { + var str = []; + if (options.trustedDomains) { + if (typeof options.trustedDomains === "string") { + str.push("trustedDomain=" + options.trustedDomains); + } else { + str.push("trustedDomain=" + options.trustedDomains.join(",")); + } + } + return str.join("&"); + }; + var _inArray = function(elem, array) { + if (array.indexOf) { + return array.indexOf(elem); + } + for (var i = 0, length = array.length; i < length; i++) { + if (array[i] === elem) { + return i; + } + } + return -1; + }; + var _prepGlue = function(elements) { + if (typeof elements === "string") throw new TypeError("ZeroClipboard doesn't accept query strings."); + if (!elements.length) return [ elements ]; + return elements; + }; + var ZeroClipboard = function(elements, options) { + if (elements) (ZeroClipboard.prototype._singleton || this).glue(elements); + if (ZeroClipboard.prototype._singleton) return ZeroClipboard.prototype._singleton; + ZeroClipboard.prototype._singleton = this; + this.options = {}; + for (var kd in _defaults) this.options[kd] = _defaults[kd]; + for (var ko in options) this.options[ko] = options[ko]; + this.handlers = {}; + if (ZeroClipboard.detectFlashSupport()) _bridge(); + }; + var currentElement, gluedElements = []; + ZeroClipboard.prototype.setCurrent = function(element) { + currentElement = element; + this.reposition(); + if (element.getAttribute("title")) { + this.setTitle(element.getAttribute("title")); + } + this.setHandCursor(_getStyle(element, "cursor") == "pointer"); + }; + ZeroClipboard.prototype.setText = function(newText) { + if (newText && newText !== "") { + this.options.text = newText; + if (this.ready()) this.flashBridge.setText(newText); + } + }; + ZeroClipboard.prototype.setTitle = function(newTitle) { + if (newTitle && newTitle !== "") this.htmlBridge.setAttribute("title", newTitle); + }; + ZeroClipboard.prototype.setSize = function(width, height) { + if (this.ready()) this.flashBridge.setSize(width, height); + }; + ZeroClipboard.prototype.setHandCursor = function(enabled) { + if (this.ready()) this.flashBridge.setHandCursor(enabled); + }; + ZeroClipboard.version = "1.1.7"; + var _defaults = { + moviePath: "ZeroClipboard.swf", + trustedDomains: null, + text: null, + hoverClass: "zeroclipboard-is-hover", + activeClass: "zeroclipboard-is-active", + allowScriptAccess: "sameDomain" + }; + ZeroClipboard.setDefaults = function(options) { + for (var ko in options) _defaults[ko] = options[ko]; + }; + ZeroClipboard.destroy = function() { + ZeroClipboard.prototype._singleton.unglue(gluedElements); + var bridge = ZeroClipboard.prototype._singleton.htmlBridge; + bridge.parentNode.removeChild(bridge); + delete ZeroClipboard.prototype._singleton; + }; + ZeroClipboard.detectFlashSupport = function() { + var hasFlash = false; + try { + if (new ActiveXObject("ShockwaveFlash.ShockwaveFlash")) { + hasFlash = true; + } + } catch (error) { + if (navigator.mimeTypes["application/x-shockwave-flash"]) { + hasFlash = true; + } + } + return hasFlash; + }; + var _bridge = function() { + var client = ZeroClipboard.prototype._singleton; + var container = document.getElementById("global-zeroclipboard-html-bridge"); + if (!container) { + var html = ' '; + container = document.createElement("div"); + container.id = "global-zeroclipboard-html-bridge"; + container.setAttribute("class", "global-zeroclipboard-container"); + container.setAttribute("data-clipboard-ready", false); + container.style.position = "absolute"; + container.style.left = "-9999px"; + container.style.top = "-9999px"; + container.style.width = "15px"; + container.style.height = "15px"; + container.style.zIndex = "9999"; + container.innerHTML = html; + document.body.appendChild(container); + } + client.htmlBridge = container; + client.flashBridge = document["global-zeroclipboard-flash-bridge"] || container.children[0].lastElementChild; + }; + ZeroClipboard.prototype.resetBridge = function() { + this.htmlBridge.style.left = "-9999px"; + this.htmlBridge.style.top = "-9999px"; + this.htmlBridge.removeAttribute("title"); + this.htmlBridge.removeAttribute("data-clipboard-text"); + _removeClass(currentElement, this.options.activeClass); + currentElement = null; + this.options.text = null; + }; + ZeroClipboard.prototype.ready = function() { + var ready = this.htmlBridge.getAttribute("data-clipboard-ready"); + return ready === "true" || ready === true; + }; + ZeroClipboard.prototype.reposition = function() { + if (!currentElement) return false; + var pos = _getDOMObjectPosition(currentElement); + var topOffset = $(currentElement).hasClass("pullright") ? $(".form-horizontal").scrollTop() : 0; + this.htmlBridge.style.top = pos.top - topOffset + "px"; + this.htmlBridge.style.left = pos.left + "px"; + this.htmlBridge.style.width = pos.width + "px"; + this.htmlBridge.style.height = pos.height + "px"; + this.htmlBridge.style.zIndex = pos.zIndex + 1; + this.setSize(pos.width, pos.height); + }; + ZeroClipboard.dispatch = function(eventName, args) { + ZeroClipboard.prototype._singleton.receiveEvent(eventName, args); + }; + ZeroClipboard.prototype.on = function(eventName, func) { + var events = eventName.toString().split(/\s/g); + for (var i = 0; i < events.length; i++) { + eventName = events[i].toLowerCase().replace(/^on/, ""); + if (!this.handlers[eventName]) this.handlers[eventName] = func; + } + if (this.handlers.noflash && !ZeroClipboard.detectFlashSupport()) { + this.receiveEvent("onNoFlash", null); + } + }; + ZeroClipboard.prototype.addEventListener = ZeroClipboard.prototype.on; + ZeroClipboard.prototype.off = function(eventName, func) { + var events = eventName.toString().split(/\s/g); + for (var i = 0; i < events.length; i++) { + eventName = events[i].toLowerCase().replace(/^on/, ""); + for (var event in this.handlers) { + if (event === eventName && this.handlers[event] === func) { + delete this.handlers[event]; + } + } + } + }; + ZeroClipboard.prototype.removeEventListener = ZeroClipboard.prototype.off; + ZeroClipboard.prototype.receiveEvent = function(eventName, args) { + eventName = eventName.toString().toLowerCase().replace(/^on/, ""); + var element = currentElement; + switch (eventName) { + case "load": + if (args && parseFloat(args.flashVersion.replace(",", ".").replace(/[^0-9\.]/gi, "")) < 10) { + this.receiveEvent("onWrongFlash", { + flashVersion: args.flashVersion + }); + return; + } + this.htmlBridge.setAttribute("data-clipboard-ready", true); + break; + case "mouseover": + _addClass(element, this.options.hoverClass); + break; + case "mouseout": + _removeClass(element, this.options.hoverClass); + this.resetBridge(); + break; + case "mousedown": + _addClass(element, this.options.activeClass); + break; + case "mouseup": + _removeClass(element, this.options.activeClass); + break; + case "datarequested": + var targetId = element.getAttribute("data-clipboard-target"), targetEl = !targetId ? null : document.getElementById(targetId); + if (targetEl) { + var textContent = targetEl.value || targetEl.textContent || targetEl.innerText; + if (textContent) this.setText(textContent); + } else { + var defaultText = element.getAttribute("data-clipboard-text"); + if (defaultText) this.setText(defaultText); + } + break; + case "complete": + this.options.text = null; + break; + } + if (this.handlers[eventName]) { + var func = this.handlers[eventName]; + if (typeof func == "function") { + func.call(element, this, args); + } else if (typeof func == "string") { + window[func].call(element, this, args); + } + } + }; + ZeroClipboard.prototype.glue = function(elements) { + elements = _prepGlue(elements); + for (var i = 0; i < elements.length; i++) { + if (_inArray(elements[i], gluedElements) == -1) { + gluedElements.push(elements[i]); + _addEventHandler(elements[i], "mouseover", _elementMouseOver); + } + } + }; + ZeroClipboard.prototype.unglue = function(elements) { + elements = _prepGlue(elements); + for (var i = 0; i < elements.length; i++) { + _removeEventHandler(elements[i], "mouseover", _elementMouseOver); + var arrayIndex = _inArray(elements[i], gluedElements); + if (arrayIndex != -1) gluedElements.splice(arrayIndex, 1); + } + }; + if (typeof module !== "undefined") { + module.exports = ZeroClipboard; + } else if (typeof define === "function" && define.amd) { + define(function() { + return ZeroClipboard; + }); + } else { + window.ZeroClipboard = ZeroClipboard; + } +})(); +(function(kmc) { + + /* + * TODO: + * Use ng-view for preview template + * Use filters for delivery + */ + + var Preview = kmc.Preview || {}; + + // Preview Partner Defaults + kmc.vars.previewDefaults = { + showAdvancedOptions: false, + includeKalturaLinks: (!kmc.vars.ignore_seo_links), + includeSeoMetadata: (!kmc.vars.ignore_entry_seo), + deliveryType: kmc.vars.default_delivery_type, + embedType: kmc.vars.default_embed_code_type, + secureEmbed: kmc.vars.embed_code_protocol_https + }; + + // Check for current protocol and update secureEmbed + if(window.location.protocol == 'https:') { + kmc.vars.previewDefaults.secureEmbed = true; + } + + Preview.storageName = 'previewDefaults'; + Preview.el = '#previewModal'; + Preview.iframeContainer = 'previewIframe'; + + // We use this flag to ignore all change evnets when we initilize the preview ( on page start up ) + // We will set that to false once Preview is opened. + Preview.ignoreChangeEvents = true; + + // Set generator + Preview.getGenerator = function() { + if(!this.generator) { + this.generator = new kEmbedCodeGenerator({ + host: kmc.vars.embed_host, + securedHost: kmc.vars.embed_host_https, + partnerId: kmc.vars.partner_id, + includeKalturaLinks: kmc.vars.previewDefaults.includeKalturaLinks + }); + } + return this.generator; + }; + + Preview.clipboard = new ZeroClipboard($('.copy-code'), { + moviePath: "/lib/flash/ZeroClipboard.swf", + trustedDomains: ['*'], + allowScriptAccess: "always" + }); + + Preview.clipboard.on('complete', function() { + var $this = $(this); + // Mark embed code as selected + $('#' + $this.data('clipboard-target')).select(); + // Close preview + if($this.data('close') === true) { + Preview.closeModal(Preview.el); + } + }); + + Preview.objectToArray = function(obj) { + var arr = []; + for(var key in obj) { + obj[key].id = key; + arr.push(obj[key]); + } + return arr; + }; + + Preview.getObjectById = function(id, arr) { + var result = $.grep(arr, function(e) { + return e.id == id; + }); + return(result.length) ? result[0] : false; + }; + + Preview.getDefault = function(setting) { + var defaults = localStorage.getItem(Preview.storageName); + if(defaults) { + defaults = JSON.parse(defaults); + } else { + defaults = kmc.vars.previewDefaults; + } + if(defaults[setting] !== undefined) { + return defaults[setting]; + } + return null; + }; + + Preview.savePreviewState = function() { + var previewService = this.Service; + var defaults = { + embedType: previewService.get('embedType'), + secureEmbed: previewService.get('secureEmbed'), + includeSeoMetadata: previewService.get('includeSeo'), + deliveryType: previewService.get('deliveryType').id, + showAdvancedOptions: previewService.get('showAdvancedOptions') + }; + // Save defaults to localStorage + localStorage.setItem(Preview.storageName, JSON.stringify(defaults)); + }; + + Preview.getDeliveryTypeFlashVars = function(deliveryType) { + // Not delivery type, exit + if(!deliveryType) return {}; + + // Get original delivery type flashvars + var originalFlashVars = (deliveryType.flashvars) ? deliveryType.flashvars : {}; + + // Clone flashVars object + var newFlashVars = $.extend({}, originalFlashVars); + + // Add streamerType and mediaProtocol flashVars + if(deliveryType.streamerType) + newFlashVars.streamerType = deliveryType.streamerType; + + if(deliveryType.mediaProtocol) + newFlashVars.mediaProtocol = deliveryType.mediaProtocol; + + // Return the new Flashvars object + return newFlashVars; + }; + + Preview.getPreviewTitle = function(options) { + if(options.entryMeta && options.entryMeta.name) { + return 'Embedding: ' + options.entryMeta.name; + } + if(options.playlistName) { + return 'Playlist: ' + options.playlistName; + } + if(options.playerOnly) { + return 'Player Name:' + options.name; + } + }; + + Preview.openPreviewEmbed = function(options, previewService) { + + var _this = this; + var el = _this.el; + + // Enable preview events + this.ignoreChangeEvents = false; + + var defaults = { + entryId: null, + entryMeta: {}, + playlistId: null, + playlistName: null, + previewOnly: null, + liveBitrates: null, + playerOnly: false, + uiConfId: null, + name: null + }; + + options = $.extend({}, defaults, options); + previewService.disableEvents(); + // In case of live entry preview, set delivery type to auto + if( options.liveBitrates ) { + previewService.set('live', true); + previewService.setDeliveryType('auto'); + }else{ + previewService.set('live',false); + } + // Update our players + previewService.updatePlayers(options); + previewService.enableEvents(); + // Set options + previewService.set(options); + + var title = this.getPreviewTitle(options); + + var $previewModal = $(el); + $previewModal.find(".title h2").text(title).attr('title', title); + $previewModal.find(".close").unbind('click').click(function() { + _this.closeModal(el); + }); + + // Show our preview modal + var modalHeight = $('body').height() - 173; + $previewModal.find('.content').height(modalHeight); + kmc.layout.modal.show(el, false); + }; + + Preview.closeModal = function(el) { + this.savePreviewState(); + this.emptyDiv(this.iframeContainer); + $(el).fadeOut(300, function() { + kmc.layout.overlay.hide(); + kmc.utils.hideFlash(); + }); + }; + + Preview.emptyDiv = function(divId) { + var $targetDiv = $('#' + divId); + var $previewIframe = $('#previewIframe iframe'); + if( $previewIframe.length ) { + try { + var $iframeDoc = $($previewIframe[0].contentWindow.document); + $iframeDoc.find('#framePlayerContainer').empty(); + } catch (e) {} + } + + if( $targetDiv.length ) { + $targetDiv.empty(); + return $targetDiv[0]; + } + return false; + }; + + Preview.hasIframe = function() { + return $('#' + this.iframeContainer + ' iframe').length; + }; + + Preview.getCacheSt = function() { + var d = new Date(); + return Math.floor(d.getTime() / 1000) + (15 * 60); // start caching in 15 minutes + }; + + Preview.generateIframe = function(embedCode) { + + var ltIE10 = $('html').hasClass('lt-ie10'); + var is_firefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; + var style = ''; + var container = this.emptyDiv(this.iframeContainer); + var iframe = document.createElement('iframe'); + // Reset iframe style + iframe.frameborder = "0"; + iframe.frameBorder = "0"; + iframe.marginheight="0"; + iframe.marginwidth="0"; + iframe.frameborder="0"; + iframe.setAttribute('allowFullScreen', ''); + iframe.setAttribute('webkitallowfullscreen', ''); + iframe.setAttribute('mozallowfullscreen', ''); + + container.appendChild(iframe); + + if(ltIE10 || is_firefox) { + iframe.src = this.getPreviewUrl(this.Service, true); + } else { + var newDoc = iframe.contentDocument; + newDoc.open(); + newDoc.write('' + style + '
' + embedCode + '
'); + newDoc.close(); + } + }; + + Preview.getEmbedProtocol = function(previewService, previewPlayer) { + if(previewPlayer === true) { + return location.protocol.substring(0, location.protocol.length - 1); // Get host protocol + } + return (previewService.get('secureEmbed')) ? 'https' : 'http'; + }; + + Preview.getEmbedFlashVars = function(previewService, previewPlayer) { + var protocol = this.getEmbedProtocol(previewService, previewPlayer); + var player = previewService.get('player'); + var flashVars = this.getDeliveryTypeFlashVars(previewService.get('deliveryType')); + if(previewPlayer === true) { + flashVars.ks = kmc.vars.ks; + if (previewService.get('live') == true){ + flashVars.disableEntryRedirect = true; + } + flashVars['liveAnalytics'] = { + "plugin": "false", // prevent loading the liveAnalytics plugin in v2 players + "relativeTo": "PlayerHolder", // required to prevent v1 players from getting stuck + "position": "after", // required to prevent v1 players from getting stuck + "loadingPolicy": "onDemand" // prevent v1 players from trying to load this plugin + }; + } + + var playlistId = previewService.get('playlistId'); + if(playlistId) { + // Use new kpl0Id flashvar for new players only + var html5_version = kmc.functions.getVersionFromPath(player.html5Url); + var kdpVersionCheck = kmc.functions.versionIsAtLeast(kmc.vars.min_kdp_version_for_playlist_api_v3, player.swf_version); + var html5VersionCheck = kmc.functions.versionIsAtLeast(kmc.vars.min_html5_version_for_playlist_api_v3, html5_version); + if( kdpVersionCheck && html5VersionCheck ) { + flashVars['playlistAPI.kpl0Id'] = playlistId; + } else { + flashVars['playlistAPI.autoInsert'] = 'true'; + flashVars['playlistAPI.kpl0Name'] = previewService.get('playlistName'); + flashVars['playlistAPI.kpl0Url'] = protocol + '://' + kmc.vars.api_host + '/index.php/partnerservices2/executeplaylist?' + 'partner_id=' + kmc.vars.partner_id + '&subp_id=' + kmc.vars.partner_id + '00' + '&format=8&ks={ks}&playlist_id=' + playlistId; + } + } + return flashVars; + }; + + Preview.getEmbedCode = function(previewService, previewPlayer) { + var player = previewService.get('player'); + if(!player || !previewService.get('embedType')) { + return ''; + } + var cacheSt = this.getCacheSt(); + var params = { + protocol: this.getEmbedProtocol(previewService, previewPlayer), + embedType: previewService.get('embedType'), + uiConfId: player.id, + width: player.width, + height: player.height, + entryMeta: previewService.get('entryMeta'), + includeSeoMetadata: previewService.get('includeSeo'), + playerId: 'kaltura_player_' + cacheSt, + cacheSt: cacheSt, + flashVars: this.getEmbedFlashVars(previewService, previewPlayer) + }; + + if(previewService.get('entryId')) { + params.entryId = previewService.get('entryId'); + } + + var code = this.getGenerator().getCode(params); + return code; + }; + + Preview.getPreviewUrl = function(previewService, framed) { + var player = previewService.get('player'); + if(!player || !previewService.get('embedType')) { + return ''; + } + + var protocol = this.getEmbedProtocol(previewService, framed); + var url = protocol + '://' + kmc.vars.api_host + '/index.php/extwidget/preview'; + //var url = protocol + '://' + window.location.host + '/KMC_V2/preview.php'; + url += '/partner_id/' + kmc.vars.partner_id; + url += '/uiconf_id/' + player.id; + // Add entry Id + if(previewService.get('entryId')) { + url += '/entry_id/' + previewService.get('entryId'); + } + url += '/embed/' + previewService.get('embedType'); + url += '?' + kmc.functions.flashVarsToUrl(this.getEmbedFlashVars(previewService, framed)); + if( framed === true ) { + url += '&framed=true'; + } + return url; + }; + + Preview.generateQrCode = function(url) { + var $qrCode = $('#qrcode').empty(); + if(!url) return ; + if($('html').hasClass('lt-ie9')) return; + $qrCode.qrcode({ + width: 80, + height: 80, + text: url + }); + }; + + Preview.generateShortUrl = function(url, callback) { + if(!url) return ; + kmc.client.createShortURL(url, callback); + }; + + kmc.Preview = Preview; + +})(window.kmc); + +var kmcApp = angular.module('kmcApp', ['pascalprecht.translate']); + +kmcApp.config(['$translateProvider', function ($translateProvider) { + $translateProvider.useStaticFilesLoader({ + prefix: '/locales/locale-', + suffix: '.json' + }); + + var lang = 'en'; + if (typeof localStorage != "unknown" && typeof localStorage["lang"] !== "undefined"){ + lang = localStorage["lang"]; + } + // take the first two characters + if( lang.length > 2 ){ + lang = lang.toLowerCase().substr(0,2); + } + $translateProvider.preferredLanguage(lang); +}]); + + +kmcApp.factory('previewService', ['$rootScope', function($rootScope) { + var previewProps = {}; + var disableCount = 0; + return { + get: function(key) { + if(key === undefined) return previewProps; + return previewProps[key]; + }, + set: function(key, value, quiet) { + if(typeof key == 'object') { + angular.extend(previewProps, key); + } else { + previewProps[key] = value; + } + if( !quiet && disableCount === 0 ) { + $rootScope.$broadcast('previewChanged'); + } + }, + enableEvents: function(){ + disableCount--; + }, + disableEvents: function(){ + disableCount++ + }, + updatePlayers: function(options) { + $rootScope.$broadcast('playersUpdated', options); + }, + changePlayer: function(playerId) { + $rootScope.$broadcast('changePlayer', playerId); + }, + setDeliveryType: function( deliveryTypeId ) { + $rootScope.$broadcast('changeDelivery', deliveryTypeId ); + } + }; +}]); +kmcApp.directive('showSlide', function() { + return { + //restrict it's use to attribute only. + restrict: 'A', + + //set up the directive. + link: function(scope, elem, attr) { + + //get the field to watch from the directive attribute. + var watchField = attr.showSlide; + + //set up the watch to toggle the element. + scope.$watch(attr.showSlide, function(v) { + if(v && !elem.is(':visible')) { + elem.slideDown(); + } else { + elem.slideUp(); + } + }); + } + }; +}); + +kmcApp.controller('PreviewCtrl', ['$scope', '$translate', 'previewService', function($scope, $translate, previewService) { + + var draw = function() { + if(!$scope.$$phase) { + $scope.$apply(); + } + }; + + var Preview = kmc.Preview; + Preview.playlistMode = false; + + Preview.Service = previewService; + + var updatePlayers = function(options) { + options = options || {}; + var playerId = (options.uiConfId) ? options.uiConfId : undefined; + // Exit if player not loaded + if(!kmc.vars.playlists_list && !kmc.vars.players_list) { + return ; + } + // List of players + if(options.playlistId || options.playerOnly) { + $scope.players = kmc.vars.playlists_list; + if(!Preview.playlistMode) { + Preview.playlistMode = true; + $scope.$broadcast('changePlayer', playerId); + return; + } + } else { + $scope.players = kmc.vars.players_list; + if(Preview.playlistMode || !$scope.player) { + Preview.playlistMode = false; + $scope.$broadcast('changePlayer', playerId); + return; + } + } + if(playerId){ + $scope.$broadcast('changePlayer', playerId); + } + }; + + var setDeliveryTypes = function(player) { + //if( $scope.liveBitrates && $scope.liveBitrates != false ) { + previewService.setDeliveryType('auto'); + //} + var deliveryTypes = Preview.objectToArray(kmc.vars.delivery_types); + var defaultType = $scope.deliveryType || Preview.getDefault('deliveryType'); + var validDeliveryTypes = []; + $.each(deliveryTypes, function() { + if(this.minVersion && !kmc.functions.versionIsAtLeast(this.minVersion, player.swf_version)) { + if(this.id == defaultType) { + defaultType = null; + } + return true; + } + validDeliveryTypes.push(this); + }); + // List of delivery types + $scope.deliveryTypes = validDeliveryTypes; + // Set default delivery type + if(!defaultType) { + defaultType = $scope.deliveryTypes[0].id; + } + previewService.setDeliveryType(defaultType); + }; + + var setEmbedTypes = function(player) { + var embedTypes = Preview.objectToArray(kmc.vars.embed_code_types); + var defaultType = $scope.embedType || Preview.getDefault('embedType'); + var validEmbedTypes = []; + $.each(embedTypes, function() { + // Don't add embed code that are entry only for playlists + if(Preview.playlistMode && this.entryOnly) { + if(this.id == defaultType) { + defaultType = null; + } + return true; + } + + // Check for library minimum version to eanble embed type. remove legacy embed for version 2 and up players + var libVersion = kmc.functions.getVersionFromPath(player.html5Url); + if((this.minVersion && !kmc.functions.versionIsAtLeast(this.minVersion, libVersion)) || + ((libVersion == "latest" || libVersion[0] == "2") && this.id == "legacy")) { + if(this.id == defaultType) { + defaultType = null; + } + return true; + } + validEmbedTypes.push(this); + }); + // List of embed types + $scope.embedTypes = validEmbedTypes; + // Set default embed type + if(!defaultType) { + defaultType = $scope.embedTypes[0].id; + } + $scope.embedType = defaultType; + }; + + // Set defaults + $scope.players = []; + $scope.player = null; + $scope.deliveryTypes = []; + $scope.deliveryType = null; + $scope.embedTypes = []; + $scope.embedType = null; + $scope.secureEmbed = Preview.getDefault('secureEmbed'); + $scope.includeSeo = Preview.getDefault('includeSeoMetadata'); + $scope.previewOnly = null; + $scope.playerOnly = false; + $scope.liveBitrates = false; + $scope.showAdvancedOptionsStatus = Preview.getDefault('showAdvancedOptions'); + $scope.shortLinkGenerated = false; + + // Set players on update + $scope.$on('playersUpdated', function(e, options) { + updatePlayers(options); + }); + + $scope.$on('changePlayer', function(e, playerId) { + if ( playerId || ( playerId === undefined && $scope.players && $scope.players.length )){ + playerId = ( playerId ) ? playerId : $scope.players[0].id; + $scope.player = playerId; + draw(); + } + }); + + $scope.$on('changeDelivery', function(e, deliveryTypeId) { + $scope.deliveryType = deliveryTypeId; + draw(); + }); + + $scope.showAdvancedOptions = function($event, show) { + $event.preventDefault(); + previewService.set('showAdvancedOptions', show, true); + $scope.showAdvancedOptionsStatus = show; + }; + + $scope.$watch('showAdvancedOptionsStatus', function() { + Preview.clipboard.reposition(); + }); + + // Listen to player change + $scope.$watch('player', function() { + var player = Preview.getObjectById($scope.player, $scope.players); + if(!player) { return ; } + previewService.disableEvents(); + setDeliveryTypes(player); + setEmbedTypes(player); + setTimeout(function(){ + previewService.enableEvents(); + previewService.set('player', player); + },0); + }); + $scope.$watch('deliveryType', function() { + var deliveryType = Preview.getObjectById($scope.deliveryType, $scope.deliveryTypes); + previewService.set('deliveryType', deliveryType); + if ( deliveryType.id === "hds" ){ + $scope.secureEmbed = false; + } + }); + $scope.$watch('embedType', function() { + previewService.set('embedType', $scope.embedType); + }); + $scope.$watch('secureEmbed', function() { + previewService.set('secureEmbed', $scope.secureEmbed); + }); + $scope.$watch('includeSeo', function() { + previewService.set('includeSeo', $scope.includeSeo); + }); + $scope.$watch('embedCodePreview', function() { + Preview.generateIframe($scope.embedCodePreview); + }); + $scope.$watch('previewOnly', function() { + if($scope.previewOnly) { + $scope.closeButtonText = $translate('CLOSE'); + } else { + $scope.closeButtonText = $translate('COPY_AND_CLOSE'); + } + draw(); + }); + $scope.$on('previewChanged', function() { + if(Preview.ignoreChangeEvents) return; + var previewUrl = Preview.getPreviewUrl(previewService); + $scope.embedCode = Preview.getEmbedCode(previewService); + $scope.embedCodePreview = Preview.getEmbedCode(previewService, true); + $scope.previewOnly = previewService.get('previewOnly'); + $scope.playerOnly = previewService.get('playerOnly'); + $scope.liveBitrates = previewService.get('liveBitrates'); + draw(); + // Generate Iframe if not exist + if(!Preview.hasIframe()) { + Preview.generateIframe($scope.embedCodePreview); + } + // Update Short url + $scope.previewUrl = $translate('UPDATING'); + $scope.shortLinkGenerated = false; + Preview.generateShortUrl(previewUrl, function(tinyUrl) { + if(!tinyUrl) { + // Set tinyUrl to fullUrl + tinyUrl = previewUrl; + } + $scope.shortLinkGenerated = true; + $scope.previewUrl = tinyUrl; + // Generate QR Code + Preview.generateQrCode(tinyUrl); + draw(); + }); + }); + +}]); // Prevent the page to be framed if(kmc.vars.allowFrame == false && top != window) { top.location = window.location; } @@ -3968,6 +3968,11 @@ kmc.functions = { kmc.utils.hideFlash(true); kmc.utils.openIframe(kmc.vars.base_url + '/apps/studio/' + kmc.vars.studio.version + '/index.html'); return false; + }, + openStudioV3: function(){ + kmc.utils.hideFlash(true); + kmc.utils.openIframe(kmc.vars.base_url + '/apps/studioV3/' + kmc.vars.studioV3.version + '/index.html'); + return false; }, openLiveAnalytics: function(){ kmc.utils.hideFlash(true); diff --git a/alpha/web/lib/js/kmc/6.0.11/kmc.min.js b/alpha/web/lib/js/kmc/6.0.11/kmc.min.js index b1ff153a80e..396d8913d10 100644 --- a/alpha/web/lib/js/kmc/6.0.11/kmc.min.js +++ b/alpha/web/lib/js/kmc/6.0.11/kmc.min.js @@ -1,6 +1,6 @@ -/*! KMC - v6.0.11 - 2017-09-27 +/*! KMC - v6.0.11 - 2017-12-03 * https://github.com/kaltura/KMC_V2 * Copyright (c) 2017 Amir Chervinsky; Licensed GNU */ -function openPlayer(e,t,r,a,n){n===!0&&$("#kcms")[0].alert("previewOnly from studio"),kmc.preview_embed.doPreviewEmbed("multitab_playlist",e,null,n,!0,a,!1,!1,!1)}function playlistAdded(){kmc.preview_embed.updateList(!0)}function playerAdded(){kmc.preview_embed.updateList(!1)}function md5(e){var t,r,a,n,i,o,s,l,c,u,d=function(e,t){return e<>>32-t},h=function(e,t){var r,a,n,i,o;return n=2147483648&e,i=2147483648&t,r=1073741824&e,a=1073741824&t,o=(1073741823&e)+(1073741823&t),r&a?2147483648^o^n^i:r|a?1073741824&o?3221225472^o^n^i:1073741824^o^n^i:o^n^i},p=function(e,t,r){return e&t|~e&r},f=function(e,t,r){return e&r|t&~r},m=function(e,t,r){return e^t^r},g=function(e,t,r){return t^(e|~r)},v=function(e,t,r,a,n,i,o){return e=h(e,h(h(p(t,r,a),n),o)),h(d(e,i),t)},y=function(e,t,r,a,n,i,o){return e=h(e,h(h(f(t,r,a),n),o)),h(d(e,i),t)},b=function(e,t,r,a,n,i,o){return e=h(e,h(h(m(t,r,a),n),o)),h(d(e,i),t)},w=function(e,t,r,a,n,i,o){return e=h(e,h(h(g(t,r,a),n),o)),h(d(e,i),t)},k=function(e){for(var t,r=e.length,a=r+8,n=(a-a%64)/64,i=16*(n+1),o=Array(i-1),s=0,l=0;r>l;)t=(l-l%4)/4,s=8*(l%4),o[t]=o[t]|e.charCodeAt(l)<>>29,o},_=function(e){var t,r,a="",n="";for(r=0;3>=r;r++)t=255&e>>>8*r,n="0"+t.toString(16),a+=n.substr(n.length-2,2);return a},I=[],C=7,$=12,E=17,T=22,P=5,L=9,S=14,A=20,M=4,x=11,N=16,D=23,O=6,B=10,H=15,U=21;for(e=this.utf8_encode(e),I=k(e),s=1732584193,l=4023233417,c=2562383102,u=271733878,t=I.length,r=0;t>r;r+=16)a=s,n=l,i=c,o=u,s=v(s,l,c,u,I[r+0],C,3614090360),u=v(u,s,l,c,I[r+1],$,3905402710),c=v(c,u,s,l,I[r+2],E,606105819),l=v(l,c,u,s,I[r+3],T,3250441966),s=v(s,l,c,u,I[r+4],C,4118548399),u=v(u,s,l,c,I[r+5],$,1200080426),c=v(c,u,s,l,I[r+6],E,2821735955),l=v(l,c,u,s,I[r+7],T,4249261313),s=v(s,l,c,u,I[r+8],C,1770035416),u=v(u,s,l,c,I[r+9],$,2336552879),c=v(c,u,s,l,I[r+10],E,4294925233),l=v(l,c,u,s,I[r+11],T,2304563134),s=v(s,l,c,u,I[r+12],C,1804603682),u=v(u,s,l,c,I[r+13],$,4254626195),c=v(c,u,s,l,I[r+14],E,2792965006),l=v(l,c,u,s,I[r+15],T,1236535329),s=y(s,l,c,u,I[r+1],P,4129170786),u=y(u,s,l,c,I[r+6],L,3225465664),c=y(c,u,s,l,I[r+11],S,643717713),l=y(l,c,u,s,I[r+0],A,3921069994),s=y(s,l,c,u,I[r+5],P,3593408605),u=y(u,s,l,c,I[r+10],L,38016083),c=y(c,u,s,l,I[r+15],S,3634488961),l=y(l,c,u,s,I[r+4],A,3889429448),s=y(s,l,c,u,I[r+9],P,568446438),u=y(u,s,l,c,I[r+14],L,3275163606),c=y(c,u,s,l,I[r+3],S,4107603335),l=y(l,c,u,s,I[r+8],A,1163531501),s=y(s,l,c,u,I[r+13],P,2850285829),u=y(u,s,l,c,I[r+2],L,4243563512),c=y(c,u,s,l,I[r+7],S,1735328473),l=y(l,c,u,s,I[r+12],A,2368359562),s=b(s,l,c,u,I[r+5],M,4294588738),u=b(u,s,l,c,I[r+8],x,2272392833),c=b(c,u,s,l,I[r+11],N,1839030562),l=b(l,c,u,s,I[r+14],D,4259657740),s=b(s,l,c,u,I[r+1],M,2763975236),u=b(u,s,l,c,I[r+4],x,1272893353),c=b(c,u,s,l,I[r+7],N,4139469664),l=b(l,c,u,s,I[r+10],D,3200236656),s=b(s,l,c,u,I[r+13],M,681279174),u=b(u,s,l,c,I[r+0],x,3936430074),c=b(c,u,s,l,I[r+3],N,3572445317),l=b(l,c,u,s,I[r+6],D,76029189),s=b(s,l,c,u,I[r+9],M,3654602809),u=b(u,s,l,c,I[r+12],x,3873151461),c=b(c,u,s,l,I[r+15],N,530742520),l=b(l,c,u,s,I[r+2],D,3299628645),s=w(s,l,c,u,I[r+0],O,4096336452),u=w(u,s,l,c,I[r+7],B,1126891415),c=w(c,u,s,l,I[r+14],H,2878612391),l=w(l,c,u,s,I[r+5],U,4237533241),s=w(s,l,c,u,I[r+12],O,1700485571),u=w(u,s,l,c,I[r+3],B,2399980690),c=w(c,u,s,l,I[r+10],H,4293915773),l=w(l,c,u,s,I[r+1],U,2240044497),s=w(s,l,c,u,I[r+8],O,1873313359),u=w(u,s,l,c,I[r+15],B,4264355552),c=w(c,u,s,l,I[r+6],H,2734768916),l=w(l,c,u,s,I[r+13],U,1309151649),s=w(s,l,c,u,I[r+4],O,4149444226),u=w(u,s,l,c,I[r+11],B,3174756917),c=w(c,u,s,l,I[r+2],H,718787259),l=w(l,c,u,s,I[r+9],U,3951481745),s=h(s,a),l=h(l,n),c=h(c,i),u=h(u,o);var j=_(s)+_(l)+_(c)+_(u);return j.toLowerCase()}function utf8_encode(e){if(null===e||e===void 0)return"";var t,r,a=e+"",n="",i=0;t=r=0,i=a.length;for(var o=0;i>o;o++){var s=a.charCodeAt(o),l=null;128>s?r++:l=s>127&&2048>s?String.fromCharCode(192|s>>6)+String.fromCharCode(128|63&s):String.fromCharCode(224|s>>12)+String.fromCharCode(128|63&s>>6)+String.fromCharCode(128|63&s),null!==l&&(r>t&&(n+=a.slice(t,r)),n+=l,t=r=o+1)}return r>t&&(n+=a.slice(t,i)),n}angular.module("pascalprecht.translate",["ng"]).run(["$translate",function(e){var t=e.storageKey(),r=e.storage();r?r.get(t)?e.uses(r.get(t)):angular.isString(e.preferredLanguage())?e.uses(e.preferredLanguage()):r.set(t,e.uses()):angular.isString(e.preferredLanguage())&&e.uses(e.preferredLanguage())}]),angular.module("pascalprecht.translate").provider("$translate",["$STORAGE_KEY",function(e){var t,r,a,n,i,o,s,l,c,u,d,h,p={},f=e,m=[],g=".",v=function(e,t){if(!e&&!t)return p;if(e&&!t){if(angular.isString(e))return p[e];angular.extend(p,y(e))}else angular.isObject(p[e])||(p[e]={}),angular.extend(p[e],y(t));return this},y=function(e,t,r,a){var n,i,o;t||(t=[]),r||(r={});for(n in e)e.hasOwnProperty(n)&&(o=e[n],angular.isObject(o)?y(o,t.concat(n),r,n):(i=t.length?""+t.join(g)+g+n:n,t.length&&n===a&&(keyWithShortPath=""+t.join(g),r[keyWithShortPath]="@:"+i),r[i]=o));return r};this.translations=v,this.addInterpolation=function(e){return m.push(e),this},this.useMessageFormatInterpolation=function(){return this.useInterpolation("$translateMessageFormatInterpolation")},this.useInterpolation=function(e){return l=e,this},this.preferredLanguage=function(e){return e?(t=e,this):t},this.translationNotFoundIndicator=function(e){return this.translationNotFoundIndicatorLeft(e),this.translationNotFoundIndicatorRight(e),this},this.translationNotFoundIndicatorLeft=function(e){return e?(d=e,this):d},this.translationNotFoundIndicatorRight=function(e){return e?(h=e,this):h},this.fallbackLanguage=function(e){return e?(("string"==typeof e||angular.isArray(e))&&(r=e),this):r},this.uses=function(e){if(e){if(!p[e]&&!c)throw Error("$translateProvider couldn't find translationTable for langKey: '"+e+"'");return a=e,this}return a};var b=function(e){return e?(f=e,void 0):o?o+f:f};this.storageKey=b,this.useUrlLoader=function(e){return this.useLoader("$translateUrlLoader",{url:e})},this.useStaticFilesLoader=function(e){return this.useLoader("$translateStaticFilesLoader",e)},this.useLoader=function(e,t){return c=e,u=t||{},this},this.useLocalStorage=function(){return this.useStorage("$translateLocalStorage")},this.useCookieStorage=function(){return this.useStorage("$translateCookieStorage")},this.useStorage=function(e){return i=e,this},this.storagePrefix=function(e){return e?(o=e,this):e},this.useMissingTranslationHandlerLog=function(){return this.useMissingTranslationHandler("$translateMissingTranslationHandlerLog")},this.useMissingTranslationHandler=function(e){return s=e,this},this.$get=["$log","$injector","$rootScope","$q",function(e,o,f,g){var y,w=o.get(l||"$translateDefaultInterpolation"),k=!1,_={},I=function(e){if(!e)throw"No language key specified for loading.";var t=g.defer();return f.$broadcast("$translateLoadingStart"),k=!0,o.get(c)(angular.extend(u,{key:e})).then(function(r){f.$broadcast("$translateLoadingSuccess");var a={};angular.isArray(r)?angular.forEach(r,function(e){angular.extend(a,e)}):angular.extend(a,r),k=!1,t.resolve({key:e,table:a}),f.$broadcast("$translateLoadingEnd")},function(e){f.$broadcast("$translateLoadingError"),t.reject(e),f.$broadcast("$translateLoadingEnd")}),t.promise};if(i&&(y=o.get(i),!y.get||!y.set))throw Error("Couldn't use storage '"+i+"', missing get() or set() method!");m.length>0&&angular.forEach(m,function(e){var r=o.get(e);r.setLocale(t||a),_[r.getInterpolationIdentifier()]=r});var C=function(e){if(e&&r){if(angular.isArray(r)){for(var t=r.length,n=0;t>n;n++)if(a===p[r[n]])return!1;return!0}return e!==r}return!1},$=function(e,t,n){var i=a?p[a]:p,l=n?_[n]:w;if(i&&i.hasOwnProperty(e))return angular.isString(i[e])&&"@:"===i[e].substr(0,2)?$(i[e].substr(2),t,n):l.interpolate(i[e],t);s&&!k&&o.get(s)(e,a);var c;if(a&&r&&C(a)){"string"==typeof r?(c=[],c.push(r)):c=r;for(var u=c.length,f=0;u>f;f++)if(a!==p[c[f]]){var m=p[c[f]][e];if(m){var g;return l.setLocale(c[f]),g=l.interpolate(m,t),l.setLocale(a),g}}}return d&&(e=[d,e].join(" ")),h&&(e=[e,h].join(" ")),e};if($.preferredLanguage=function(){return t},$.fallbackLanguage=function(){return r},$.proposedLanguage=function(){return n},$.storage=function(){return y},$.uses=function(e){function t(e){a=e,f.$broadcast("$translateChangeSuccess"),i&&y.set($.storageKey(),a),w.setLocale(a),angular.forEach(_,function(e,t){_[t].setLocale(a)}),r.resolve(e),f.$broadcast("$translateChangeEnd")}if(!e)return a;var r=g.defer();return f.$broadcast("$translateChangeStart"),!p[e]&&c?(n=e,I(e).then(function(e){n=void 0,v(e.key,e.table),t(e.key)},function(e){n=void 0,f.$broadcast("$translateChangeError"),r.reject(e),f.$broadcast("$translateChangeEnd")})):t(e),r.promise},$.storageKey=function(){return b()},$.refresh=function(e){function t(){i.resolve(),f.$broadcast("$translateRefreshEnd")}function n(){i.reject(),f.$broadcast("$translateRefreshEnd")}if(!c)throw Error("Couldn't refresh translation table, no loader registered!");var i=g.defer();if(e)if(p.hasOwnProperty(e)){f.$broadcast("$translateRefreshStart");var o=I(e);e===a?o.then(function(r){p[e]=r.table,$.uses(a),t()},function(){f.$broadcast("$translateChangeError"),n()}):o.then(function(r){p[e]=r.table,t()},n)}else i.reject();else{f.$broadcast("$translateRefreshStart");var s=[];if(r)if("string"==typeof r)s.push(I(r));else for(var l=r.length,u=0;l>u;u++)s.push(I(r[u]));a&&s.push(I(a)),s.length>0?g.all(s).then(function(e){for(var r in p)p.hasOwnProperty(r)&&delete p[r];for(var n=0,i=e.length;i>n;n++)v(e[n].key,e[n].table);a&&$.uses(a),t()},function(e){e===a&&f.$broadcast("$translateChangeError"),n()}):t()}return i.promise},c&&(angular.equals(p,{})&&$.uses($.uses()),r))if("string"!=typeof r||p[r])for(var E=r.length,T=0;E>T;T++)p[r[T]]||I(r[T]);else I(r);return $}]}]),angular.module("pascalprecht.translate").factory("$translateDefaultInterpolation",["$interpolate",function(e){var t,r={},a="default";return r.setLocale=function(e){t=e},r.getInterpolationIdentifier=function(){return a},r.interpolate=function(t,r){return e(t)(r)},r}]),angular.module("pascalprecht.translate").constant("$STORAGE_KEY","NG_TRANSLATE_LANG_KEY"),angular.module("pascalprecht.translate").directive("translate",["$filter","$interpolate","$parse",function(e,t,r){var a=e("translate");return{restrict:"AE",scope:!0,link:function(e,n,i){i.translateInterpolation&&(e.interpolation=i.translateInterpolation),i.$observe("translate",function(r){e.translationId=angular.equals(r,"")||void 0===r?t(n.text().replace(/^\s+|\s+$/g,""))(e.$parent):r}),i.$observe("translateValues",function(t){t&&e.$parent.$watch(function(){e.interpolateParams=r(t)(e.$parent)})}),e.$on("$translateChangeSuccess",function(){n.html(a(e.translationId,e.interpolateParams,e.interpolation))}),e.$watch("[translationId, interpolateParams]",function(){e.translationId&&n.html(a(e.translationId,e.interpolateParams,e.interpolation))},!0)}}}]),angular.module("pascalprecht.translate").filter("translate",["$parse","$translate",function(e,t){return function(r,a,n){return angular.isObject(a)||(a=e(a)()),t(r,a,n)}}]),angular.module("pascalprecht.translate").factory("$translateStaticFilesLoader",["$q","$http",function(e,t){return function(r){if(!r||!r.prefix||!r.suffix)throw Error("Couldn't load static files, no prefix or suffix specified!");var a=e.defer();return t({url:[r.prefix,r.key,r.suffix].join(""),method:"GET",params:""}).success(function(e){a.resolve(e)}).error(function(){a.reject(r.key)}),a.promise}}]),this.Handlebars={},function(e){e.VERSION="1.0.rc.2",e.helpers={},e.partials={},e.registerHelper=function(e,t,r){r&&(t.not=r),this.helpers[e]=t},e.registerPartial=function(e,t){this.partials[e]=t},e.registerHelper("helperMissing",function(e){if(2===arguments.length)return void 0;throw Error("Could not find property '"+e+"'")});var t=Object.prototype.toString,r="[object Function]";e.registerHelper("blockHelperMissing",function(a,n){var i=n.inverse||function(){},o=n.fn,s=t.call(a);return s===r&&(a=a.call(this)),a===!0?o(this):a===!1||null==a?i(this):"[object Array]"===s?a.length>0?e.helpers.each(a,n):i(this):o(a)}),e.K=function(){},e.createFrame=Object.create||function(t){e.K.prototype=t;var r=new e.K;return e.K.prototype=null,r},e.logger={DEBUG:0,INFO:1,WARN:2,ERROR:3,level:3,methodMap:{0:"debug",1:"info",2:"warn",3:"error"},log:function(t,r){if(t>=e.logger.level){var a=e.logger.methodMap[t];"undefined"!=typeof console&&console[a]&&console[a].call(console,r)}}},e.log=function(t,r){e.logger.log(t,r)},e.registerHelper("each",function(t,r){var a,n=r.fn,i=r.inverse,o=0,s="";if(r.data&&(a=e.createFrame(r.data)),t&&"object"==typeof t)if(t instanceof Array)for(var l=t.length;l>o;o++)a&&(a.index=o),s+=n(t[o],{data:a});else for(var c in t)t.hasOwnProperty(c)&&(a&&(a.key=c),s+=n(t[c],{data:a}),o++);return 0===o&&(s=i(this)),s}),e.registerHelper("if",function(a,n){var i=t.call(a);return i===r&&(a=a.call(this)),!a||e.Utils.isEmpty(a)?n.inverse(this):n.fn(this)}),e.registerHelper("unless",function(t,r){var a=r.fn,n=r.inverse;return r.fn=n,r.inverse=a,e.helpers["if"].call(this,t,r)}),e.registerHelper("with",function(e,t){return t.fn(e)}),e.registerHelper("log",function(t,r){var a=r.data&&null!=r.data.level?parseInt(r.data.level,10):1;e.log(a,t)})}(this.Handlebars);var errorProps=["description","fileName","lineNumber","message","name","number","stack"];Handlebars.Exception=function(){for(var e=Error.prototype.constructor.apply(this,arguments),t=0;errorProps.length>t;t++)this[errorProps[t]]=e[errorProps[t]]},Handlebars.Exception.prototype=Error(),Handlebars.SafeString=function(e){this.string=e},Handlebars.SafeString.prototype.toString=function(){return""+this.string},function(){var e={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},t=/[&<>"'`]/g,r=/[&<>"'`]/,a=function(t){return e[t]||"&"};Handlebars.Utils={escapeExpression:function(e){return e instanceof Handlebars.SafeString?""+e:null==e||e===!1?"":r.test(e)?e.replace(t,a):e},isEmpty:function(e){return e||0===e?"[object Array]"===Object.prototype.toString.call(e)&&0===e.length?!0:!1:!0}}}(),Handlebars.VM={template:function(e){var t={escapeExpression:Handlebars.Utils.escapeExpression,invokePartial:Handlebars.VM.invokePartial,programs:[],program:function(e,t,r){var a=this.programs[e];return r?Handlebars.VM.program(t,r):a?a:a=this.programs[e]=Handlebars.VM.program(t)},programWithDepth:Handlebars.VM.programWithDepth,noop:Handlebars.VM.noop};return function(r,a){return a=a||{},e.call(t,Handlebars,r,a.helpers,a.partials,a.data)}},programWithDepth:function(e,t){var r=Array.prototype.slice.call(arguments,2);return function(a,n){return n=n||{},e.apply(this,[a,n.data||t].concat(r))}},program:function(e,t){return function(r,a){return a=a||{},e(r,a.data||t)}},noop:function(){return""},invokePartial:function(e,t,r,a,n,i){var o={helpers:a,partials:n,data:i};if(void 0===e)throw new Handlebars.Exception("The partial "+t+" could not be found");if(e instanceof Function)return e(r,o);if(Handlebars.compile)return n[t]=Handlebars.compile(e,{data:void 0!==i}),n[t](r,o);throw new Handlebars.Exception("The partial "+t+" could not be compiled when running in runtime-only mode")}},Handlebars.template=Handlebars.VM.template,function(e,t){var r=function(e,t){var r="",a=t?t+"[":"",n=t?"]":"";for(var i in e)if("object"==typeof e[i])for(var o in e[i])r+="&"+a+encodeURIComponent(i)+"."+encodeURIComponent(o)+n+"="+encodeURIComponent(e[i][o]);else r+="&"+a+encodeURIComponent(i)+n+"="+encodeURIComponent(e[i]);return r};t.registerHelper("flashVarsUrl",function(e){return r(e,"flashvars")}),t.registerHelper("flashVarsString",function(e){return r(e)}),t.registerHelper("elAttributes",function(e){var t="";for(var r in e)t+=" "+r+'="'+e[r]+'"';return t}),t.registerHelper("kalturaLinks",function(){if(!this.includeKalturaLinks)return"";var e=t.templates.kaltura_links;return e()}),t.registerHelper("seoMetadata",function(){var e=t.templates.seo_metadata;return e(this)})}(this,this.Handlebars),function(){var e=Handlebars.template,t=Handlebars.templates=Handlebars.templates||{};t.auto=e(function(e,t,r,a,n){function i(e){var t,a,n="";return n+='
",u=r.seoMetadata,t=u||e.seoMetadata,typeof t===f?t=t.call(e,{hash:{}}):t===g&&(t=m.call(e,"seoMetadata",{hash:{}})),(t||0===t)&&(n+=t),u=r.kalturaLinks,t=u||e.kalturaLinks,typeof t===f?t=t.call(e,{hash:{}}):t===g&&(t=m.call(e,"kalturaLinks",{hash:{}})),(t||0===t)&&(n+=t),n+="
\n"}function o(e){var t,a="";return a+="&entry_id=",u=r.entryId,t=u||e.entryId,typeof t===f?t=t.call(e,{hash:{}}):t===g&&(t=m.call(e,"entryId",{hash:{}})),a+=v(t)}function s(e){var t,a="";return a+="&cache_st=",u=r.cacheSt,t=u||e.cacheSt,typeof t===f?t=t.call(e,{hash:{}}):t===g&&(t=m.call(e,"cacheSt",{hash:{}})),a+=v(t)}r=r||e.helpers;var l,c,u,d,h="",p=this,f="function",m=r.helperMissing,g=void 0,v=this.escapeExpression;return u=r.includeSeoMetadata,l=u||t.includeSeoMetadata,c=r["if"],d=p.program(1,i,n),d.hash={},d.fn=d,d.inverse=p.noop,l=c.call(t,l,d),(l||0===l)&&(h+=l),h+=''}),t.dynamic=e(function(e,t,r){r=r||e.helpers;var a,n,i,o="",s="function",l=r.helperMissing,c=void 0,u=this.escapeExpression;return o+='\n
",i=r.seoMetadata,a=i||t.seoMetadata,typeof a===s?a=a.call(t,{hash:{}}):a===c&&(a=l.call(t,"seoMetadata",{hash:{}})),(a||0===a)&&(o+=a),i=r.kalturaLinks,a=i||t.kalturaLinks,typeof a===s?a=a.call(t,{hash:{}}):a===c&&(a=l.call(t,"kalturaLinks",{hash:{}})),(a||0===a)&&(o+=a),o+="
\n"}),t.iframe=e(function(e,t,r,a,n){function i(e){var t,a="";return a+="&entry_id=",l=r.entryId,t=l||e.entryId,typeof t===h?t=t.call(e,{hash:{}}):t===f&&(t=p.call(e,"entryId",{hash:{}})),a+=m(t)}r=r||e.helpers;var o,s,l,c,u="",d=this,h="function",p=r.helperMissing,f=void 0,m=this.escapeExpression;return u+='"}),t.kaltura_links=e(function(e,t,r){return r=r||e.helpers,'Video Platform\nVideo Management \nVideo Solutions\nVideo Player'}),t.legacy=e(function(e,t,r,a,n){function i(e){var t,a="";return a+='\n'}function o(e){var t,a="";return a+='\n \n \n \n \n \n \n '}r=r||e.helpers;var s,l,c,u,d="",h=this,p="function",f=r.helperMissing,m=void 0,g=this.escapeExpression;return c=r.includeHtml5Library,s=c||t.includeHtml5Library,l=r["if"],u=h.program(1,i,n),u.hash={},u.fn=u,u.inverse=h.noop,s=l.call(t,s,u),(s||0===s)&&(d+=s),d+='\n \n \n \n \n \n \n ',c=r.includeSeoMetadata,s=c||t.includeSeoMetadata,l=r["if"],u=h.program(3,o,n),u.hash={},u.fn=u,u.inverse=h.noop,s=l.call(t,s,u),(s||0===s)&&(d+=s),c=r.kalturaLinks,s=c||t.kalturaLinks,typeof s===p?s=s.call(t,{hash:{}}):s===m&&(s=f.call(t,"kalturaLinks",{hash:{}})),(s||0===s)&&(d+=s),d+="\n"}),t.seo_metadata=e(function(e,t,r,a,n){function i(e){var t,a="";return a+='\n\n\n\n\n\n\n'}r=r||e.helpers;var o,s,l,c,u=this,d="function",h=r.helperMissing,p=void 0,f=this.escapeExpression;return l=r.includeSeoMetadata,o=l||t.includeSeoMetadata,s=r["if"],c=u.program(1,i,n),c.hash={},c.fn=c,c.inverse=u.noop,o=s.call(t,o,c),o||0===o?o:""})}(),Array.prototype.indexOf||(Array.prototype.indexOf=function(e){"use strict";if(null==this)throw new TypeError;var t=Object(this),r=t.length>>>0;if(0===r)return-1;var a=0;if(arguments.length>1&&(a=Number(arguments[1]),a!==a?a=0:0!==a&&1/0!==a&&a!==-1/0&&(a=(a>0||-1)*Math.floor(Math.abs(a)))),a>=r)return-1;for(var n=a>=0?a:Math.max(r-Math.abs(a),0);r>n;n++)if(n in t&&t[n]===e)return n;return-1}),Object.keys||(Object.keys=function(){var e=Object.prototype.hasOwnProperty,t=!{toString:null}.propertyIsEnumerable("toString"),r=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],a=r.length;return function(n){if("object"!=typeof n&&"function"!=typeof n||null===n)throw new TypeError("Object.keys called on non-object");var i=[];for(var o in n)e.call(n,o)&&i.push(o);if(t)for(var s=0;a>s;s++)e.call(n,r[s])&&i.push(r[s]);return i}}()),function(e,t){var r=function(e){this.init(e)};r.prototype={types:["auto","dynamic","thumb","iframe","legacy"],required:["widgetId","partnerId","uiConfId"],defaults:{embedType:"auto",playerId:"kaltura_player",protocol:"http",host:"www.kaltura.com",securedHost:"www.kaltura.com",widgetId:null,partnerId:null,cacheSt:null,uiConfId:null,entryId:null,entryMeta:{},width:400,height:330,attributes:{},flashVars:{},includeKalturaLinks:!0,includeSeoMetadata:!1,includeHtml5Library:!0},extend:function(e,t){for(var r in t)t.hasOwnProperty(r)&&!e.hasOwnProperty(r)&&(e[r]=t[r]);return e},isNull:function(e){return e.length&&e.length>0?!1:e.length&&0===e.length?!0:"object"==typeof e?Object.keys(e).length>0?!1:!0:!e},init:function(e){if(e=e||{},this.defaults,typeof Handlebars===t)throw"Handlebars is not defined, please include Handlebars.js before this script";return"object"==typeof e&&(this.options=this.extend(e,this.defaults)),!this.config("widgetId")&&this.config("partnerId")&&this.config("widgetId","_"+this.config("partnerId")),this},config:function(e,r){return r===t&&"string"==typeof e&&this.options.hasOwnProperty(e)?this.options[e]:e===t&&r===t?this.options:("string"==typeof e&&r!==t&&(this.options[e]=r),null)},checkRequiredParams:function(e){var t=this.required.length,r=0;for(r;t>r;r++)if(this.isNull(e[this.required[r]]))throw"Missing required parameter: "+this.required[r]},checkValidType:function(e){var t=-1!==this.types.indexOf(e)?!0:!1;if(!t)throw"Embed type: "+e+" is not valid. Available types: "+this.types.join(",")},getTemplate:function(e){return e="thumb"==e?"dynamic":e,e&&Handlebars.templates&&Handlebars.templates[e]?Handlebars.templates[e]:null},isKWidgetEmbed:function(e){return"dynamic"==e||"thumb"==e?!0:!1},getHost:function(e){return"http"===e.protocol?e.host:e.securedHost},getScriptUrl:function(e){return e.protocol+"://"+this.getHost(e)+"/p/"+e.partnerId+"/sp/"+e.partnerId+"00/embedIframeJs/uiconf_id/"+e.uiConfId+"/partner_id/"+e.partnerId},getSwfUrl:function(e){var t=e.cacheSt?"/cache_st/"+e.cacheSt:"",r=e.entryId?"/entry_id/"+e.entryId:"";return e.protocol+"://"+this.getHost(e)+"/index.php/kwidget"+t+"/wid/"+e.widgetId+"/uiconf_id/"+e.uiConfId+r},getAttributes:function(e){var t={};return(this.isKWidgetEmbed(e.embedType)||e.includeSeoMetadata)&&(t.style="width: "+e.width+"px; height: "+e.height+"px;"),e.includeSeoMetadata&&("legacy"==e.embedType?(t["xmlns:dc"]="http://purl.org/dc/terms/",t["xmlns:media"]="http://search.yahoo.com/searchmonkey/media/",t.rel="media:video",t.resource=this.getSwfUrl(e)):(t.itemprop="video",t["itemscope itemtype"]="http://schema.org/VideoObject")),t},getEmbedObject:function(e){var t={targetId:e.playerId,wid:e.widgetId,uiconf_id:e.uiConfId,flashvars:e.flashVars};return e.cacheSt&&(t.cache_st=e.cacheSt),e.entryId&&(t.entry_id=e.entryId),JSON.stringify(t,null,2)},getCode:function(e){var r=e===t?{}:this.extend({},e);r=this.extend(r,this.config()),!r.widgetId&&r.partnerId&&(r.widgetId="_"+r.partnerId),this.checkRequiredParams(r),this.checkValidType(r.embedType);var a=this.getTemplate(r.embedType);if(!a)throw"Template: "+r.embedType+" is not defined as Handlebars template";var n={host:this.getHost(r),scriptUrl:this.getScriptUrl(r),attributes:this.getAttributes(r)};return"legacy"===r.embedType&&(n.swfUrl=this.getSwfUrl(r)),this.isKWidgetEmbed(r.embedType)&&(n.embedMethod="dynamic"==r.embedType?"embed":"thumbEmbed",n.kWidgetObject=this.getEmbedObject(r)),n=this.extend(n,r),a(n)}},e.kEmbedCodeGenerator=r}(this),function(e){e.fn.qrcode=function(t){function r(e){this.mode=s.MODE_8BIT_BYTE,this.data=e}function a(e,t){this.typeNumber=e,this.errorCorrectLevel=t,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}function n(e,t){if(void 0==e.length)throw Error(e.length+"/"+t);for(var r=0;e.length>r&&0==e[r];)r++;this.num=Array(e.length-r+t);for(var a=0;e.length-r>a;a++)this.num[a]=e[a+r]}function i(e,t){this.totalCount=e,this.dataCount=t}function o(){this.buffer=[],this.length=0}r.prototype={getLength:function(){return this.data.length},write:function(e){for(var t=0;this.data.length>t;t++)e.put(this.data.charCodeAt(t),8) +function openPlayer(e,t,r,a,n){n===!0&&$("#kcms")[0].alert("previewOnly from studio"),kmc.preview_embed.doPreviewEmbed("multitab_playlist",e,null,n,!0,a,!1,!1,!1)}function playlistAdded(){kmc.preview_embed.updateList(!0)}function playerAdded(){kmc.preview_embed.updateList(!1)}function md5(e){var t,r,a,n,i,o,s,l,c,u,d=function(e,t){return e<>>32-t},h=function(e,t){var r,a,n,i,o;return n=2147483648&e,i=2147483648&t,r=1073741824&e,a=1073741824&t,o=(1073741823&e)+(1073741823&t),r&a?2147483648^o^n^i:r|a?1073741824&o?3221225472^o^n^i:1073741824^o^n^i:o^n^i},p=function(e,t,r){return e&t|~e&r},f=function(e,t,r){return e&r|t&~r},m=function(e,t,r){return e^t^r},g=function(e,t,r){return t^(e|~r)},v=function(e,t,r,a,n,i,o){return e=h(e,h(h(p(t,r,a),n),o)),h(d(e,i),t)},y=function(e,t,r,a,n,i,o){return e=h(e,h(h(f(t,r,a),n),o)),h(d(e,i),t)},b=function(e,t,r,a,n,i,o){return e=h(e,h(h(m(t,r,a),n),o)),h(d(e,i),t)},k=function(e,t,r,a,n,i,o){return e=h(e,h(h(g(t,r,a),n),o)),h(d(e,i),t)},w=function(e){for(var t,r=e.length,a=r+8,n=(a-a%64)/64,i=16*(n+1),o=Array(i-1),s=0,l=0;r>l;)t=(l-l%4)/4,s=8*(l%4),o[t]=o[t]|e.charCodeAt(l)<>>29,o},_=function(e){var t,r,a="",n="";for(r=0;3>=r;r++)t=255&e>>>8*r,n="0"+t.toString(16),a+=n.substr(n.length-2,2);return a},I=[],C=7,$=12,E=17,T=22,P=5,L=9,S=14,A=20,M=4,x=11,N=16,D=23,O=6,B=10,H=15,U=21;for(e=this.utf8_encode(e),I=w(e),s=1732584193,l=4023233417,c=2562383102,u=271733878,t=I.length,r=0;t>r;r+=16)a=s,n=l,i=c,o=u,s=v(s,l,c,u,I[r+0],C,3614090360),u=v(u,s,l,c,I[r+1],$,3905402710),c=v(c,u,s,l,I[r+2],E,606105819),l=v(l,c,u,s,I[r+3],T,3250441966),s=v(s,l,c,u,I[r+4],C,4118548399),u=v(u,s,l,c,I[r+5],$,1200080426),c=v(c,u,s,l,I[r+6],E,2821735955),l=v(l,c,u,s,I[r+7],T,4249261313),s=v(s,l,c,u,I[r+8],C,1770035416),u=v(u,s,l,c,I[r+9],$,2336552879),c=v(c,u,s,l,I[r+10],E,4294925233),l=v(l,c,u,s,I[r+11],T,2304563134),s=v(s,l,c,u,I[r+12],C,1804603682),u=v(u,s,l,c,I[r+13],$,4254626195),c=v(c,u,s,l,I[r+14],E,2792965006),l=v(l,c,u,s,I[r+15],T,1236535329),s=y(s,l,c,u,I[r+1],P,4129170786),u=y(u,s,l,c,I[r+6],L,3225465664),c=y(c,u,s,l,I[r+11],S,643717713),l=y(l,c,u,s,I[r+0],A,3921069994),s=y(s,l,c,u,I[r+5],P,3593408605),u=y(u,s,l,c,I[r+10],L,38016083),c=y(c,u,s,l,I[r+15],S,3634488961),l=y(l,c,u,s,I[r+4],A,3889429448),s=y(s,l,c,u,I[r+9],P,568446438),u=y(u,s,l,c,I[r+14],L,3275163606),c=y(c,u,s,l,I[r+3],S,4107603335),l=y(l,c,u,s,I[r+8],A,1163531501),s=y(s,l,c,u,I[r+13],P,2850285829),u=y(u,s,l,c,I[r+2],L,4243563512),c=y(c,u,s,l,I[r+7],S,1735328473),l=y(l,c,u,s,I[r+12],A,2368359562),s=b(s,l,c,u,I[r+5],M,4294588738),u=b(u,s,l,c,I[r+8],x,2272392833),c=b(c,u,s,l,I[r+11],N,1839030562),l=b(l,c,u,s,I[r+14],D,4259657740),s=b(s,l,c,u,I[r+1],M,2763975236),u=b(u,s,l,c,I[r+4],x,1272893353),c=b(c,u,s,l,I[r+7],N,4139469664),l=b(l,c,u,s,I[r+10],D,3200236656),s=b(s,l,c,u,I[r+13],M,681279174),u=b(u,s,l,c,I[r+0],x,3936430074),c=b(c,u,s,l,I[r+3],N,3572445317),l=b(l,c,u,s,I[r+6],D,76029189),s=b(s,l,c,u,I[r+9],M,3654602809),u=b(u,s,l,c,I[r+12],x,3873151461),c=b(c,u,s,l,I[r+15],N,530742520),l=b(l,c,u,s,I[r+2],D,3299628645),s=k(s,l,c,u,I[r+0],O,4096336452),u=k(u,s,l,c,I[r+7],B,1126891415),c=k(c,u,s,l,I[r+14],H,2878612391),l=k(l,c,u,s,I[r+5],U,4237533241),s=k(s,l,c,u,I[r+12],O,1700485571),u=k(u,s,l,c,I[r+3],B,2399980690),c=k(c,u,s,l,I[r+10],H,4293915773),l=k(l,c,u,s,I[r+1],U,2240044497),s=k(s,l,c,u,I[r+8],O,1873313359),u=k(u,s,l,c,I[r+15],B,4264355552),c=k(c,u,s,l,I[r+6],H,2734768916),l=k(l,c,u,s,I[r+13],U,1309151649),s=k(s,l,c,u,I[r+4],O,4149444226),u=k(u,s,l,c,I[r+11],B,3174756917),c=k(c,u,s,l,I[r+2],H,718787259),l=k(l,c,u,s,I[r+9],U,3951481745),s=h(s,a),l=h(l,n),c=h(c,i),u=h(u,o);var j=_(s)+_(l)+_(c)+_(u);return j.toLowerCase()}function utf8_encode(e){if(null===e||e===void 0)return"";var t,r,a=e+"",n="",i=0;t=r=0,i=a.length;for(var o=0;i>o;o++){var s=a.charCodeAt(o),l=null;128>s?r++:l=s>127&&2048>s?String.fromCharCode(192|s>>6)+String.fromCharCode(128|63&s):String.fromCharCode(224|s>>12)+String.fromCharCode(128|63&s>>6)+String.fromCharCode(128|63&s),null!==l&&(r>t&&(n+=a.slice(t,r)),n+=l,t=r=o+1)}return r>t&&(n+=a.slice(t,i)),n}angular.module("pascalprecht.translate",["ng"]).run(["$translate",function(e){var t=e.storageKey(),r=e.storage();r?r.get(t)?e.uses(r.get(t)):angular.isString(e.preferredLanguage())?e.uses(e.preferredLanguage()):r.set(t,e.uses()):angular.isString(e.preferredLanguage())&&e.uses(e.preferredLanguage())}]),angular.module("pascalprecht.translate").provider("$translate",["$STORAGE_KEY",function(e){var t,r,a,n,i,o,s,l,c,u,d,h,p={},f=e,m=[],g=".",v=function(e,t){if(!e&&!t)return p;if(e&&!t){if(angular.isString(e))return p[e];angular.extend(p,y(e))}else angular.isObject(p[e])||(p[e]={}),angular.extend(p[e],y(t));return this},y=function(e,t,r,a){var n,i,o;t||(t=[]),r||(r={});for(n in e)e.hasOwnProperty(n)&&(o=e[n],angular.isObject(o)?y(o,t.concat(n),r,n):(i=t.length?""+t.join(g)+g+n:n,t.length&&n===a&&(keyWithShortPath=""+t.join(g),r[keyWithShortPath]="@:"+i),r[i]=o));return r};this.translations=v,this.addInterpolation=function(e){return m.push(e),this},this.useMessageFormatInterpolation=function(){return this.useInterpolation("$translateMessageFormatInterpolation")},this.useInterpolation=function(e){return l=e,this},this.preferredLanguage=function(e){return e?(t=e,this):t},this.translationNotFoundIndicator=function(e){return this.translationNotFoundIndicatorLeft(e),this.translationNotFoundIndicatorRight(e),this},this.translationNotFoundIndicatorLeft=function(e){return e?(d=e,this):d},this.translationNotFoundIndicatorRight=function(e){return e?(h=e,this):h},this.fallbackLanguage=function(e){return e?(("string"==typeof e||angular.isArray(e))&&(r=e),this):r},this.uses=function(e){if(e){if(!p[e]&&!c)throw Error("$translateProvider couldn't find translationTable for langKey: '"+e+"'");return a=e,this}return a};var b=function(e){return e?(f=e,void 0):o?o+f:f};this.storageKey=b,this.useUrlLoader=function(e){return this.useLoader("$translateUrlLoader",{url:e})},this.useStaticFilesLoader=function(e){return this.useLoader("$translateStaticFilesLoader",e)},this.useLoader=function(e,t){return c=e,u=t||{},this},this.useLocalStorage=function(){return this.useStorage("$translateLocalStorage")},this.useCookieStorage=function(){return this.useStorage("$translateCookieStorage")},this.useStorage=function(e){return i=e,this},this.storagePrefix=function(e){return e?(o=e,this):e},this.useMissingTranslationHandlerLog=function(){return this.useMissingTranslationHandler("$translateMissingTranslationHandlerLog")},this.useMissingTranslationHandler=function(e){return s=e,this},this.$get=["$log","$injector","$rootScope","$q",function(e,o,f,g){var y,k=o.get(l||"$translateDefaultInterpolation"),w=!1,_={},I=function(e){if(!e)throw"No language key specified for loading.";var t=g.defer();return f.$broadcast("$translateLoadingStart"),w=!0,o.get(c)(angular.extend(u,{key:e})).then(function(r){f.$broadcast("$translateLoadingSuccess");var a={};angular.isArray(r)?angular.forEach(r,function(e){angular.extend(a,e)}):angular.extend(a,r),w=!1,t.resolve({key:e,table:a}),f.$broadcast("$translateLoadingEnd")},function(e){f.$broadcast("$translateLoadingError"),t.reject(e),f.$broadcast("$translateLoadingEnd")}),t.promise};if(i&&(y=o.get(i),!y.get||!y.set))throw Error("Couldn't use storage '"+i+"', missing get() or set() method!");m.length>0&&angular.forEach(m,function(e){var r=o.get(e);r.setLocale(t||a),_[r.getInterpolationIdentifier()]=r});var C=function(e){if(e&&r){if(angular.isArray(r)){for(var t=r.length,n=0;t>n;n++)if(a===p[r[n]])return!1;return!0}return e!==r}return!1},$=function(e,t,n){var i=a?p[a]:p,l=n?_[n]:k;if(i&&i.hasOwnProperty(e))return angular.isString(i[e])&&"@:"===i[e].substr(0,2)?$(i[e].substr(2),t,n):l.interpolate(i[e],t);s&&!w&&o.get(s)(e,a);var c;if(a&&r&&C(a)){"string"==typeof r?(c=[],c.push(r)):c=r;for(var u=c.length,f=0;u>f;f++)if(a!==p[c[f]]){var m=p[c[f]][e];if(m){var g;return l.setLocale(c[f]),g=l.interpolate(m,t),l.setLocale(a),g}}}return d&&(e=[d,e].join(" ")),h&&(e=[e,h].join(" ")),e};if($.preferredLanguage=function(){return t},$.fallbackLanguage=function(){return r},$.proposedLanguage=function(){return n},$.storage=function(){return y},$.uses=function(e){function t(e){a=e,f.$broadcast("$translateChangeSuccess"),i&&y.set($.storageKey(),a),k.setLocale(a),angular.forEach(_,function(e,t){_[t].setLocale(a)}),r.resolve(e),f.$broadcast("$translateChangeEnd")}if(!e)return a;var r=g.defer();return f.$broadcast("$translateChangeStart"),!p[e]&&c?(n=e,I(e).then(function(e){n=void 0,v(e.key,e.table),t(e.key)},function(e){n=void 0,f.$broadcast("$translateChangeError"),r.reject(e),f.$broadcast("$translateChangeEnd")})):t(e),r.promise},$.storageKey=function(){return b()},$.refresh=function(e){function t(){i.resolve(),f.$broadcast("$translateRefreshEnd")}function n(){i.reject(),f.$broadcast("$translateRefreshEnd")}if(!c)throw Error("Couldn't refresh translation table, no loader registered!");var i=g.defer();if(e)if(p.hasOwnProperty(e)){f.$broadcast("$translateRefreshStart");var o=I(e);e===a?o.then(function(r){p[e]=r.table,$.uses(a),t()},function(){f.$broadcast("$translateChangeError"),n()}):o.then(function(r){p[e]=r.table,t()},n)}else i.reject();else{f.$broadcast("$translateRefreshStart");var s=[];if(r)if("string"==typeof r)s.push(I(r));else for(var l=r.length,u=0;l>u;u++)s.push(I(r[u]));a&&s.push(I(a)),s.length>0?g.all(s).then(function(e){for(var r in p)p.hasOwnProperty(r)&&delete p[r];for(var n=0,i=e.length;i>n;n++)v(e[n].key,e[n].table);a&&$.uses(a),t()},function(e){e===a&&f.$broadcast("$translateChangeError"),n()}):t()}return i.promise},c&&(angular.equals(p,{})&&$.uses($.uses()),r))if("string"!=typeof r||p[r])for(var E=r.length,T=0;E>T;T++)p[r[T]]||I(r[T]);else I(r);return $}]}]),angular.module("pascalprecht.translate").factory("$translateDefaultInterpolation",["$interpolate",function(e){var t,r={},a="default";return r.setLocale=function(e){t=e},r.getInterpolationIdentifier=function(){return a},r.interpolate=function(t,r){return e(t)(r)},r}]),angular.module("pascalprecht.translate").constant("$STORAGE_KEY","NG_TRANSLATE_LANG_KEY"),angular.module("pascalprecht.translate").directive("translate",["$filter","$interpolate","$parse",function(e,t,r){var a=e("translate");return{restrict:"AE",scope:!0,link:function(e,n,i){i.translateInterpolation&&(e.interpolation=i.translateInterpolation),i.$observe("translate",function(r){e.translationId=angular.equals(r,"")||void 0===r?t(n.text().replace(/^\s+|\s+$/g,""))(e.$parent):r}),i.$observe("translateValues",function(t){t&&e.$parent.$watch(function(){e.interpolateParams=r(t)(e.$parent)})}),e.$on("$translateChangeSuccess",function(){n.html(a(e.translationId,e.interpolateParams,e.interpolation))}),e.$watch("[translationId, interpolateParams]",function(){e.translationId&&n.html(a(e.translationId,e.interpolateParams,e.interpolation))},!0)}}}]),angular.module("pascalprecht.translate").filter("translate",["$parse","$translate",function(e,t){return function(r,a,n){return angular.isObject(a)||(a=e(a)()),t(r,a,n)}}]),angular.module("pascalprecht.translate").factory("$translateStaticFilesLoader",["$q","$http",function(e,t){return function(r){if(!r||!r.prefix||!r.suffix)throw Error("Couldn't load static files, no prefix or suffix specified!");var a=e.defer();return t({url:[r.prefix,r.key,r.suffix].join(""),method:"GET",params:""}).success(function(e){a.resolve(e)}).error(function(){a.reject(r.key)}),a.promise}}]),this.Handlebars={},function(e){e.VERSION="1.0.rc.2",e.helpers={},e.partials={},e.registerHelper=function(e,t,r){r&&(t.not=r),this.helpers[e]=t},e.registerPartial=function(e,t){this.partials[e]=t},e.registerHelper("helperMissing",function(e){if(2===arguments.length)return void 0;throw Error("Could not find property '"+e+"'")});var t=Object.prototype.toString,r="[object Function]";e.registerHelper("blockHelperMissing",function(a,n){var i=n.inverse||function(){},o=n.fn,s=t.call(a);return s===r&&(a=a.call(this)),a===!0?o(this):a===!1||null==a?i(this):"[object Array]"===s?a.length>0?e.helpers.each(a,n):i(this):o(a)}),e.K=function(){},e.createFrame=Object.create||function(t){e.K.prototype=t;var r=new e.K;return e.K.prototype=null,r},e.logger={DEBUG:0,INFO:1,WARN:2,ERROR:3,level:3,methodMap:{0:"debug",1:"info",2:"warn",3:"error"},log:function(t,r){if(t>=e.logger.level){var a=e.logger.methodMap[t];"undefined"!=typeof console&&console[a]&&console[a].call(console,r)}}},e.log=function(t,r){e.logger.log(t,r)},e.registerHelper("each",function(t,r){var a,n=r.fn,i=r.inverse,o=0,s="";if(r.data&&(a=e.createFrame(r.data)),t&&"object"==typeof t)if(t instanceof Array)for(var l=t.length;l>o;o++)a&&(a.index=o),s+=n(t[o],{data:a});else for(var c in t)t.hasOwnProperty(c)&&(a&&(a.key=c),s+=n(t[c],{data:a}),o++);return 0===o&&(s=i(this)),s}),e.registerHelper("if",function(a,n){var i=t.call(a);return i===r&&(a=a.call(this)),!a||e.Utils.isEmpty(a)?n.inverse(this):n.fn(this)}),e.registerHelper("unless",function(t,r){var a=r.fn,n=r.inverse;return r.fn=n,r.inverse=a,e.helpers["if"].call(this,t,r)}),e.registerHelper("with",function(e,t){return t.fn(e)}),e.registerHelper("log",function(t,r){var a=r.data&&null!=r.data.level?parseInt(r.data.level,10):1;e.log(a,t)})}(this.Handlebars);var errorProps=["description","fileName","lineNumber","message","name","number","stack"];Handlebars.Exception=function(){for(var e=Error.prototype.constructor.apply(this,arguments),t=0;errorProps.length>t;t++)this[errorProps[t]]=e[errorProps[t]]},Handlebars.Exception.prototype=Error(),Handlebars.SafeString=function(e){this.string=e},Handlebars.SafeString.prototype.toString=function(){return""+this.string},function(){var e={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},t=/[&<>"'`]/g,r=/[&<>"'`]/,a=function(t){return e[t]||"&"};Handlebars.Utils={escapeExpression:function(e){return e instanceof Handlebars.SafeString?""+e:null==e||e===!1?"":r.test(e)?e.replace(t,a):e},isEmpty:function(e){return e||0===e?"[object Array]"===Object.prototype.toString.call(e)&&0===e.length?!0:!1:!0}}}(),Handlebars.VM={template:function(e){var t={escapeExpression:Handlebars.Utils.escapeExpression,invokePartial:Handlebars.VM.invokePartial,programs:[],program:function(e,t,r){var a=this.programs[e];return r?Handlebars.VM.program(t,r):a?a:a=this.programs[e]=Handlebars.VM.program(t)},programWithDepth:Handlebars.VM.programWithDepth,noop:Handlebars.VM.noop};return function(r,a){return a=a||{},e.call(t,Handlebars,r,a.helpers,a.partials,a.data)}},programWithDepth:function(e,t){var r=Array.prototype.slice.call(arguments,2);return function(a,n){return n=n||{},e.apply(this,[a,n.data||t].concat(r))}},program:function(e,t){return function(r,a){return a=a||{},e(r,a.data||t)}},noop:function(){return""},invokePartial:function(e,t,r,a,n,i){var o={helpers:a,partials:n,data:i};if(void 0===e)throw new Handlebars.Exception("The partial "+t+" could not be found");if(e instanceof Function)return e(r,o);if(Handlebars.compile)return n[t]=Handlebars.compile(e,{data:void 0!==i}),n[t](r,o);throw new Handlebars.Exception("The partial "+t+" could not be compiled when running in runtime-only mode")}},Handlebars.template=Handlebars.VM.template,function(e,t){var r=function(e,t){var r="",a=t?t+"[":"",n=t?"]":"";for(var i in e)if("object"==typeof e[i])for(var o in e[i])r+="&"+a+encodeURIComponent(i)+"."+encodeURIComponent(o)+n+"="+encodeURIComponent(e[i][o]);else r+="&"+a+encodeURIComponent(i)+n+"="+encodeURIComponent(e[i]);return r};t.registerHelper("flashVarsUrl",function(e){return r(e,"flashvars")}),t.registerHelper("flashVarsString",function(e){return r(e)}),t.registerHelper("elAttributes",function(e){var t="";for(var r in e)t+=" "+r+'="'+e[r]+'"';return t}),t.registerHelper("kalturaLinks",function(){if(!this.includeKalturaLinks)return"";var e=t.templates.kaltura_links;return e()}),t.registerHelper("seoMetadata",function(){var e=t.templates.seo_metadata;return e(this)})}(this,this.Handlebars),function(){var e=Handlebars.template,t=Handlebars.templates=Handlebars.templates||{};t.auto=e(function(e,t,r,a,n){function i(e){var t,a,n="";return n+='
",u=r.seoMetadata,t=u||e.seoMetadata,typeof t===f?t=t.call(e,{hash:{}}):t===g&&(t=m.call(e,"seoMetadata",{hash:{}})),(t||0===t)&&(n+=t),u=r.kalturaLinks,t=u||e.kalturaLinks,typeof t===f?t=t.call(e,{hash:{}}):t===g&&(t=m.call(e,"kalturaLinks",{hash:{}})),(t||0===t)&&(n+=t),n+="
\n"}function o(e){var t,a="";return a+="&entry_id=",u=r.entryId,t=u||e.entryId,typeof t===f?t=t.call(e,{hash:{}}):t===g&&(t=m.call(e,"entryId",{hash:{}})),a+=v(t)}function s(e){var t,a="";return a+="&cache_st=",u=r.cacheSt,t=u||e.cacheSt,typeof t===f?t=t.call(e,{hash:{}}):t===g&&(t=m.call(e,"cacheSt",{hash:{}})),a+=v(t)}r=r||e.helpers;var l,c,u,d,h="",p=this,f="function",m=r.helperMissing,g=void 0,v=this.escapeExpression;return u=r.includeSeoMetadata,l=u||t.includeSeoMetadata,c=r["if"],d=p.program(1,i,n),d.hash={},d.fn=d,d.inverse=p.noop,l=c.call(t,l,d),(l||0===l)&&(h+=l),h+=''}),t.dynamic=e(function(e,t,r){r=r||e.helpers;var a,n,i,o="",s="function",l=r.helperMissing,c=void 0,u=this.escapeExpression;return o+='\n
",i=r.seoMetadata,a=i||t.seoMetadata,typeof a===s?a=a.call(t,{hash:{}}):a===c&&(a=l.call(t,"seoMetadata",{hash:{}})),(a||0===a)&&(o+=a),i=r.kalturaLinks,a=i||t.kalturaLinks,typeof a===s?a=a.call(t,{hash:{}}):a===c&&(a=l.call(t,"kalturaLinks",{hash:{}})),(a||0===a)&&(o+=a),o+="
\n"}),t.iframe=e(function(e,t,r,a,n){function i(e){var t,a="";return a+="&entry_id=",l=r.entryId,t=l||e.entryId,typeof t===h?t=t.call(e,{hash:{}}):t===f&&(t=p.call(e,"entryId",{hash:{}})),a+=m(t)}r=r||e.helpers;var o,s,l,c,u="",d=this,h="function",p=r.helperMissing,f=void 0,m=this.escapeExpression;return u+='"}),t.kaltura_links=e(function(e,t,r){return r=r||e.helpers,'Video Platform\nVideo Management \nVideo Solutions\nVideo Player'}),t.legacy=e(function(e,t,r,a,n){function i(e){var t,a="";return a+='\n'}function o(e){var t,a="";return a+='\n \n \n \n \n \n \n '}r=r||e.helpers;var s,l,c,u,d="",h=this,p="function",f=r.helperMissing,m=void 0,g=this.escapeExpression;return c=r.includeHtml5Library,s=c||t.includeHtml5Library,l=r["if"],u=h.program(1,i,n),u.hash={},u.fn=u,u.inverse=h.noop,s=l.call(t,s,u),(s||0===s)&&(d+=s),d+='\n \n \n \n \n \n \n ',c=r.includeSeoMetadata,s=c||t.includeSeoMetadata,l=r["if"],u=h.program(3,o,n),u.hash={},u.fn=u,u.inverse=h.noop,s=l.call(t,s,u),(s||0===s)&&(d+=s),c=r.kalturaLinks,s=c||t.kalturaLinks,typeof s===p?s=s.call(t,{hash:{}}):s===m&&(s=f.call(t,"kalturaLinks",{hash:{}})),(s||0===s)&&(d+=s),d+="\n"}),t.seo_metadata=e(function(e,t,r,a,n){function i(e){var t,a="";return a+='\n\n\n\n\n\n\n'}r=r||e.helpers;var o,s,l,c,u=this,d="function",h=r.helperMissing,p=void 0,f=this.escapeExpression;return l=r.includeSeoMetadata,o=l||t.includeSeoMetadata,s=r["if"],c=u.program(1,i,n),c.hash={},c.fn=c,c.inverse=u.noop,o=s.call(t,o,c),o||0===o?o:""})}(),Array.prototype.indexOf||(Array.prototype.indexOf=function(e){"use strict";if(null==this)throw new TypeError;var t=Object(this),r=t.length>>>0;if(0===r)return-1;var a=0;if(arguments.length>1&&(a=Number(arguments[1]),a!==a?a=0:0!==a&&1/0!==a&&a!==-1/0&&(a=(a>0||-1)*Math.floor(Math.abs(a)))),a>=r)return-1;for(var n=a>=0?a:Math.max(r-Math.abs(a),0);r>n;n++)if(n in t&&t[n]===e)return n;return-1}),Object.keys||(Object.keys=function(){var e=Object.prototype.hasOwnProperty,t=!{toString:null}.propertyIsEnumerable("toString"),r=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],a=r.length;return function(n){if("object"!=typeof n&&"function"!=typeof n||null===n)throw new TypeError("Object.keys called on non-object");var i=[];for(var o in n)e.call(n,o)&&i.push(o);if(t)for(var s=0;a>s;s++)e.call(n,r[s])&&i.push(r[s]);return i}}()),function(e,t){var r=function(e){this.init(e)};r.prototype={types:["auto","dynamic","thumb","iframe","legacy"],required:["widgetId","partnerId","uiConfId"],defaults:{embedType:"auto",playerId:"kaltura_player",protocol:"http",host:"www.kaltura.com",securedHost:"www.kaltura.com",widgetId:null,partnerId:null,cacheSt:null,uiConfId:null,entryId:null,entryMeta:{},width:400,height:330,attributes:{},flashVars:{},includeKalturaLinks:!0,includeSeoMetadata:!1,includeHtml5Library:!0},extend:function(e,t){for(var r in t)t.hasOwnProperty(r)&&!e.hasOwnProperty(r)&&(e[r]=t[r]);return e},isNull:function(e){return e.length&&e.length>0?!1:e.length&&0===e.length?!0:"object"==typeof e?Object.keys(e).length>0?!1:!0:!e},init:function(e){if(e=e||{},this.defaults,typeof Handlebars===t)throw"Handlebars is not defined, please include Handlebars.js before this script";return"object"==typeof e&&(this.options=this.extend(e,this.defaults)),!this.config("widgetId")&&this.config("partnerId")&&this.config("widgetId","_"+this.config("partnerId")),this},config:function(e,r){return r===t&&"string"==typeof e&&this.options.hasOwnProperty(e)?this.options[e]:e===t&&r===t?this.options:("string"==typeof e&&r!==t&&(this.options[e]=r),null)},checkRequiredParams:function(e){var t=this.required.length,r=0;for(r;t>r;r++)if(this.isNull(e[this.required[r]]))throw"Missing required parameter: "+this.required[r]},checkValidType:function(e){var t=-1!==this.types.indexOf(e)?!0:!1;if(!t)throw"Embed type: "+e+" is not valid. Available types: "+this.types.join(",")},getTemplate:function(e){return e="thumb"==e?"dynamic":e,e&&Handlebars.templates&&Handlebars.templates[e]?Handlebars.templates[e]:null},isKWidgetEmbed:function(e){return"dynamic"==e||"thumb"==e?!0:!1},getHost:function(e){return"http"===e.protocol?e.host:e.securedHost},getScriptUrl:function(e){return e.protocol+"://"+this.getHost(e)+"/p/"+e.partnerId+"/sp/"+e.partnerId+"00/embedIframeJs/uiconf_id/"+e.uiConfId+"/partner_id/"+e.partnerId},getSwfUrl:function(e){var t=e.cacheSt?"/cache_st/"+e.cacheSt:"",r=e.entryId?"/entry_id/"+e.entryId:"";return e.protocol+"://"+this.getHost(e)+"/index.php/kwidget"+t+"/wid/"+e.widgetId+"/uiconf_id/"+e.uiConfId+r},getAttributes:function(e){var t={};return(this.isKWidgetEmbed(e.embedType)||e.includeSeoMetadata)&&(t.style="width: "+e.width+"px; height: "+e.height+"px;"),e.includeSeoMetadata&&("legacy"==e.embedType?(t["xmlns:dc"]="http://purl.org/dc/terms/",t["xmlns:media"]="http://search.yahoo.com/searchmonkey/media/",t.rel="media:video",t.resource=this.getSwfUrl(e)):(t.itemprop="video",t["itemscope itemtype"]="http://schema.org/VideoObject")),t},getEmbedObject:function(e){var t={targetId:e.playerId,wid:e.widgetId,uiconf_id:e.uiConfId,flashvars:e.flashVars};return e.cacheSt&&(t.cache_st=e.cacheSt),e.entryId&&(t.entry_id=e.entryId),JSON.stringify(t,null,2)},getCode:function(e){var r=e===t?{}:this.extend({},e);r=this.extend(r,this.config()),!r.widgetId&&r.partnerId&&(r.widgetId="_"+r.partnerId),this.checkRequiredParams(r),this.checkValidType(r.embedType);var a=this.getTemplate(r.embedType);if(!a)throw"Template: "+r.embedType+" is not defined as Handlebars template";var n={host:this.getHost(r),scriptUrl:this.getScriptUrl(r),attributes:this.getAttributes(r)};return"legacy"===r.embedType&&(n.swfUrl=this.getSwfUrl(r)),this.isKWidgetEmbed(r.embedType)&&(n.embedMethod="dynamic"==r.embedType?"embed":"thumbEmbed",n.kWidgetObject=this.getEmbedObject(r)),n=this.extend(n,r),a(n)}},e.kEmbedCodeGenerator=r}(this),function(e){e.fn.qrcode=function(t){function r(e){this.mode=s.MODE_8BIT_BYTE,this.data=e}function a(e,t){this.typeNumber=e,this.errorCorrectLevel=t,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}function n(e,t){if(void 0==e.length)throw Error(e.length+"/"+t);for(var r=0;e.length>r&&0==e[r];)r++;this.num=Array(e.length-r+t);for(var a=0;e.length-r>a;a++)this.num[a]=e[a+r]}function i(e,t){this.totalCount=e,this.dataCount=t}function o(){this.buffer=[],this.length=0}r.prototype={getLength:function(){return this.data.length},write:function(e){for(var t=0;this.data.length>t;t++)e.put(this.data.charCodeAt(t),8) }},a.prototype={addData:function(e){var t=new r(e);this.dataList.push(t),this.dataCache=null},isDark:function(e,t){if(0>e||e>=this.moduleCount||0>t||t>=this.moduleCount)throw Error(e+","+t);return this.modules[e][t]},getModuleCount:function(){return this.moduleCount},make:function(){if(1>this.typeNumber){var e=1;for(e=1;40>e;e++){for(var t=i.getRSBlocks(e,this.errorCorrectLevel),r=new o,a=0,n=0;t.length>n;n++)a+=t[n].dataCount;for(var n=0;this.dataList.length>n;n++){var s=this.dataList[n];r.put(s.mode,4),r.put(s.getLength(),u.getLengthInBits(s.mode,e)),s.write(r)}if(8*a>=r.getLengthInBits())break}this.typeNumber=e}this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(e,t){this.moduleCount=4*this.typeNumber+17,this.modules=Array(this.moduleCount);for(var r=0;this.moduleCount>r;r++){this.modules[r]=Array(this.moduleCount);for(var n=0;this.moduleCount>n;n++)this.modules[r][n]=null}this.setupPositionProbePattern(0,0),this.setupPositionProbePattern(this.moduleCount-7,0),this.setupPositionProbePattern(0,this.moduleCount-7),this.setupPositionAdjustPattern(),this.setupTimingPattern(),this.setupTypeInfo(e,t),this.typeNumber>=7&&this.setupTypeNumber(e),null==this.dataCache&&(this.dataCache=a.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,t)},setupPositionProbePattern:function(e,t){for(var r=-1;7>=r;r++)if(!(-1>=e+r||e+r>=this.moduleCount))for(var a=-1;7>=a;a++)-1>=t+a||t+a>=this.moduleCount||(this.modules[e+r][t+a]=r>=0&&6>=r&&(0==a||6==a)||a>=0&&6>=a&&(0==r||6==r)||r>=2&&4>=r&&a>=2&&4>=a?!0:!1)},getBestMaskPattern:function(){for(var e=0,t=0,r=0;8>r;r++){this.makeImpl(!0,r);var a=u.getLostPoint(this);(0==r||e>a)&&(e=a,t=r)}return t},createMovieClip:function(e,t,r){var a=e.createEmptyMovieClip(t,r),n=1;this.make();for(var i=0;this.modules.length>i;i++)for(var o=i*n,s=0;this.modules[i].length>s;s++){var l=s*n,c=this.modules[i][s];c&&(a.beginFill(0,100),a.moveTo(l,o),a.lineTo(l+n,o),a.lineTo(l+n,o+n),a.lineTo(l,o+n),a.endFill())}return a},setupTimingPattern:function(){for(var e=8;this.moduleCount-8>e;e++)null==this.modules[e][6]&&(this.modules[e][6]=0==e%2);for(var t=8;this.moduleCount-8>t;t++)null==this.modules[6][t]&&(this.modules[6][t]=0==t%2)},setupPositionAdjustPattern:function(){for(var e=u.getPatternPosition(this.typeNumber),t=0;e.length>t;t++)for(var r=0;e.length>r;r++){var a=e[t],n=e[r];if(null==this.modules[a][n])for(var i=-2;2>=i;i++)for(var o=-2;2>=o;o++)this.modules[a+i][n+o]=-2==i||2==i||-2==o||2==o||0==i&&0==o?!0:!1}},setupTypeNumber:function(e){for(var t=u.getBCHTypeNumber(this.typeNumber),r=0;18>r;r++){var a=!e&&1==(1&t>>r);this.modules[Math.floor(r/3)][r%3+this.moduleCount-8-3]=a}for(var r=0;18>r;r++){var a=!e&&1==(1&t>>r);this.modules[r%3+this.moduleCount-8-3][Math.floor(r/3)]=a}},setupTypeInfo:function(e,t){for(var r=this.errorCorrectLevel<<3|t,a=u.getBCHTypeInfo(r),n=0;15>n;n++){var i=!e&&1==(1&a>>n);6>n?this.modules[n][8]=i:8>n?this.modules[n+1][8]=i:this.modules[this.moduleCount-15+n][8]=i}for(var n=0;15>n;n++){var i=!e&&1==(1&a>>n);8>n?this.modules[8][this.moduleCount-n-1]=i:9>n?this.modules[8][15-n-1+1]=i:this.modules[8][15-n-1]=i}this.modules[this.moduleCount-8][8]=!e},mapData:function(e,t){for(var r=-1,a=this.moduleCount-1,n=7,i=0,o=this.moduleCount-1;o>0;o-=2)for(6==o&&o--;;){for(var s=0;2>s;s++)if(null==this.modules[a][o-s]){var l=!1;e.length>i&&(l=1==(1&e[i]>>>n));var c=u.getMask(t,a,o-s);c&&(l=!l),this.modules[a][o-s]=l,n--,-1==n&&(i++,n=7)}if(a+=r,0>a||a>=this.moduleCount){a-=r,r=-r;break}}}},a.PAD0=236,a.PAD1=17,a.createData=function(e,t,r){for(var n=i.getRSBlocks(e,t),s=new o,l=0;r.length>l;l++){var c=r[l];s.put(c.mode,4),s.put(c.getLength(),u.getLengthInBits(c.mode,e)),c.write(s)}for(var d=0,l=0;n.length>l;l++)d+=n[l].dataCount;if(s.getLengthInBits()>8*d)throw Error("code length overflow. ("+s.getLengthInBits()+">"+8*d+")");for(8*d>=s.getLengthInBits()+4&&s.put(0,4);0!=s.getLengthInBits()%8;)s.putBit(!1);for(;;){if(s.getLengthInBits()>=8*d)break;if(s.put(a.PAD0,8),s.getLengthInBits()>=8*d)break;s.put(a.PAD1,8)}return a.createBytes(s,n)},a.createBytes=function(e,t){for(var r=0,a=0,i=0,o=Array(t.length),s=Array(t.length),l=0;t.length>l;l++){var c=t[l].dataCount,d=t[l].totalCount-c;a=Math.max(a,c),i=Math.max(i,d),o[l]=Array(c);for(var h=0;o[l].length>h;h++)o[l][h]=255&e.buffer[h+r];r+=c;var p=u.getErrorCorrectPolynomial(d),f=new n(o[l],p.getLength()-1),m=f.mod(p);s[l]=Array(p.getLength()-1);for(var h=0;s[l].length>h;h++){var g=h+m.getLength()-s[l].length;s[l][h]=g>=0?m.get(g):0}}for(var v=0,h=0;t.length>h;h++)v+=t[h].totalCount;for(var y=Array(v),b=0,h=0;a>h;h++)for(var l=0;t.length>l;l++)o[l].length>h&&(y[b++]=o[l][h]);for(var h=0;i>h;h++)for(var l=0;t.length>l;l++)s[l].length>h&&(y[b++]=s[l][h]);return y};for(var s={MODE_NUMBER:1,MODE_ALPHA_NUM:2,MODE_8BIT_BYTE:4,MODE_KANJI:8},l={L:1,M:0,Q:3,H:2},c={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7},u={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:1335,G18:7973,G15_MASK:21522,getBCHTypeInfo:function(e){for(var t=e<<10;u.getBCHDigit(t)-u.getBCHDigit(u.G15)>=0;)t^=u.G15<=0;)t^=u.G18<>>=1;return t},getPatternPosition:function(e){return u.PATTERN_POSITION_TABLE[e-1]},getMask:function(e,t,r){switch(e){case c.PATTERN000:return 0==(t+r)%2;case c.PATTERN001:return 0==t%2;case c.PATTERN010:return 0==r%3;case c.PATTERN011:return 0==(t+r)%3;case c.PATTERN100:return 0==(Math.floor(t/2)+Math.floor(r/3))%2;case c.PATTERN101:return 0==t*r%2+t*r%3;case c.PATTERN110:return 0==(t*r%2+t*r%3)%2;case c.PATTERN111:return 0==(t*r%3+(t+r)%2)%2;default:throw Error("bad maskPattern:"+e)}},getErrorCorrectPolynomial:function(e){for(var t=new n([1],0),r=0;e>r;r++)t=t.multiply(new n([1,d.gexp(r)],0));return t},getLengthInBits:function(e,t){if(t>=1&&10>t)switch(e){case s.MODE_NUMBER:return 10;case s.MODE_ALPHA_NUM:return 9;case s.MODE_8BIT_BYTE:return 8;case s.MODE_KANJI:return 8;default:throw Error("mode:"+e)}else if(27>t)switch(e){case s.MODE_NUMBER:return 12;case s.MODE_ALPHA_NUM:return 11;case s.MODE_8BIT_BYTE:return 16;case s.MODE_KANJI:return 10;default:throw Error("mode:"+e)}else{if(!(41>t))throw Error("type:"+t);switch(e){case s.MODE_NUMBER:return 14;case s.MODE_ALPHA_NUM:return 13;case s.MODE_8BIT_BYTE:return 16;case s.MODE_KANJI:return 12;default:throw Error("mode:"+e)}}},getLostPoint:function(e){for(var t=e.getModuleCount(),r=0,a=0;t>a;a++)for(var n=0;t>n;n++){for(var i=0,o=e.isDark(a,n),s=-1;1>=s;s++)if(!(0>a+s||a+s>=t))for(var l=-1;1>=l;l++)0>n+l||n+l>=t||(0!=s||0!=l)&&o==e.isDark(a+s,n+l)&&i++;i>5&&(r+=3+i-5)}for(var a=0;t-1>a;a++)for(var n=0;t-1>n;n++){var c=0;e.isDark(a,n)&&c++,e.isDark(a+1,n)&&c++,e.isDark(a,n+1)&&c++,e.isDark(a+1,n+1)&&c++,(0==c||4==c)&&(r+=3)}for(var a=0;t>a;a++)for(var n=0;t-6>n;n++)e.isDark(a,n)&&!e.isDark(a,n+1)&&e.isDark(a,n+2)&&e.isDark(a,n+3)&&e.isDark(a,n+4)&&!e.isDark(a,n+5)&&e.isDark(a,n+6)&&(r+=40);for(var n=0;t>n;n++)for(var a=0;t-6>a;a++)e.isDark(a,n)&&!e.isDark(a+1,n)&&e.isDark(a+2,n)&&e.isDark(a+3,n)&&e.isDark(a+4,n)&&!e.isDark(a+5,n)&&e.isDark(a+6,n)&&(r+=40);for(var u=0,n=0;t>n;n++)for(var a=0;t>a;a++)e.isDark(a,n)&&u++;var d=Math.abs(100*u/t/t-50)/5;return r+=10*d}},d={glog:function(e){if(1>e)throw Error("glog("+e+")");return d.LOG_TABLE[e]},gexp:function(e){for(;0>e;)e+=255;for(;e>=256;)e-=255;return d.EXP_TABLE[e]},EXP_TABLE:Array(256),LOG_TABLE:Array(256)},h=0;8>h;h++)d.EXP_TABLE[h]=1<h;h++)d.EXP_TABLE[h]=d.EXP_TABLE[h-4]^d.EXP_TABLE[h-5]^d.EXP_TABLE[h-6]^d.EXP_TABLE[h-8];for(var h=0;255>h;h++)d.LOG_TABLE[d.EXP_TABLE[h]]=h;n.prototype={get:function(e){return this.num[e]},getLength:function(){return this.num.length},multiply:function(e){for(var t=Array(this.getLength()+e.getLength()-1),r=0;this.getLength()>r;r++)for(var a=0;e.getLength()>a;a++)t[r+a]^=d.gexp(d.glog(this.get(r))+d.glog(e.get(a)));return new n(t,0)},mod:function(e){if(0>this.getLength()-e.getLength())return this;for(var t=d.glog(this.get(0))-d.glog(e.get(0)),r=Array(this.getLength()),a=0;this.getLength()>a;a++)r[a]=this.get(a);for(var a=0;e.getLength()>a;a++)r[a]^=d.gexp(d.glog(e.get(a))+t);return new n(r,0).mod(e)}},i.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]],i.getRSBlocks=function(e,t){var r=i.getRsBlockTable(e,t);if(void 0==r)throw Error("bad rs block @ typeNumber:"+e+"/errorCorrectLevel:"+t);for(var a=r.length/3,n=[],o=0;a>o;o++)for(var s=r[3*o+0],l=r[3*o+1],c=r[3*o+2],u=0;s>u;u++)n.push(new i(l,c));return n},i.getRsBlockTable=function(e,t){switch(t){case l.L:return i.RS_BLOCK_TABLE[4*(e-1)+0];case l.M:return i.RS_BLOCK_TABLE[4*(e-1)+1];case l.Q:return i.RS_BLOCK_TABLE[4*(e-1)+2];case l.H:return i.RS_BLOCK_TABLE[4*(e-1)+3];default:return void 0}},o.prototype={get:function(e){var t=Math.floor(e/8);return 1==(1&this.buffer[t]>>>7-e%8)},put:function(e,t){for(var r=0;t>r;r++)this.putBit(1==(1&e>>>t-r-1))},getLengthInBits:function(){return this.length},putBit:function(e){var t=Math.floor(this.length/8);t>=this.buffer.length&&this.buffer.push(0),e&&(this.buffer[t]|=128>>>this.length%8),this.length++}},"string"==typeof t&&(t={text:t}),t=e.extend({},{render:"canvas",width:256,height:256,typeNumber:-1,correctLevel:l.H,background:"#ffffff",foreground:"#000000"},t);var p=function(){var e=new a(t.typeNumber,t.correctLevel);e.addData(t.text),e.make();var r=document.createElement("canvas");r.width=t.width,r.height=t.height;for(var n=r.getContext("2d"),i=t.width/e.getModuleCount(),o=t.height/e.getModuleCount(),s=0;e.getModuleCount()>s;s++)for(var l=0;e.getModuleCount()>l;l++){n.fillStyle=e.isDark(s,l)?t.foreground:t.background;var c=Math.ceil((l+1)*i)-Math.floor(l*i),u=Math.ceil((s+1)*i)-Math.floor(s*i);n.fillRect(Math.round(l*i),Math.round(s*o),c,u)}return r},f=function(){var r=new a(t.typeNumber,t.correctLevel);r.addData(t.text),r.make();for(var n=e("
").css("width",t.width+"px").css("height",t.height+"px").css("border","0px").css("border-collapse","collapse").css("background-color",t.background),i=t.width/r.getModuleCount(),o=t.height/r.getModuleCount(),s=0;r.getModuleCount()>s;s++)for(var l=e("").css("height",o+"px").appendTo(n),c=0;r.getModuleCount()>c;c++)e("").css("width",i+"px").css("background-color",r.isDark(s,c)?t.foreground:t.background).appendTo(l);return n};return this.each(function(){var r="canvas"==t.render?p():f();e(r).appendTo(this)})}}(jQuery),window.XDomainRequest&&jQuery.ajaxTransport(function(e){if(e.crossDomain&&e.async){e.timeout&&(e.xdrTimeout=e.timeout,delete e.timeout);var t;return{send:function(r,a){function n(e,r,n,i){t.onload=t.onerror=t.ontimeout=jQuery.noop,t=void 0,a(e,r,n,i)}t=new XDomainRequest,t.onload=function(){n(200,"OK",{text:t.responseText},"Content-Type: "+t.contentType)},t.onerror=function(){n(404,"Not Found")},t.onprogress=jQuery.noop,t.ontimeout=function(){n(0,"timeout")},t.timeout=e.xdrTimeout||Number.MAX_VALUE,t.open(e.type,e.url),t.send(e.hasContent&&e.data||null)},abort:function(){t&&(t.onerror=jQuery.noop,t.abort())}}}}),function(){"use strict";var e,t=function(e,t){var r=e.style[t];if(e.currentStyle?r=e.currentStyle[t]:window.getComputedStyle&&(r=document.defaultView.getComputedStyle(e,null).getPropertyValue(t)),"auto"==r&&"cursor"==t)for(var a=["a"],n=0;a.length>n;n++)if(e.tagName.toLowerCase()==a[n])return"pointer";return r},r=function(e){if(h.prototype._singleton){e||(e=window.event);var t;this!==window?t=this:e.target?t=e.target:e.srcElement&&(t=e.srcElement),h.prototype._singleton.setCurrent(t)}},a=function(e,t,r){e.addEventListener?e.addEventListener(t,r,!1):e.attachEvent&&e.attachEvent("on"+t,r)},n=function(e,t,r){e.removeEventListener?e.removeEventListener(t,r,!1):e.detachEvent&&e.detachEvent("on"+t,r)},i=function(e,t){if(e.addClass)return e.addClass(t),e;if(t&&"string"==typeof t){var r=(t||"").split(/\s+/);if(1===e.nodeType)if(e.className){for(var a=" "+e.className+" ",n=e.className,i=0,o=r.length;o>i;i++)0>a.indexOf(" "+r[i]+" ")&&(n+=" "+r[i]);e.className=n.replace(/^\s+|\s+$/g,"")}else e.className=t}return e},o=function(e,t){if(e.removeClass)return e.removeClass(t),e;if(t&&"string"==typeof t||void 0===t){var r=(t||"").split(/\s+/);if(1===e.nodeType&&e.className)if(t){for(var a=(" "+e.className+" ").replace(/[\n\t]/g," "),n=0,i=r.length;i>n;n++)a=a.replace(" "+r[n]+" "," ");e.className=a.replace(/^\s+|\s+$/g,"")}else e.className=""}return e},s=function(e){var r={left:0,top:0,width:e.width||e.offsetWidth||0,height:e.height||e.offsetHeight||0,zIndex:9999},a=t(e,"zIndex");for(a&&"auto"!=a&&(r.zIndex=parseInt(a,10));e;){var n=parseInt(t(e,"borderLeftWidth"),10),i=parseInt(t(e,"borderTopWidth"),10);r.left+=isNaN(e.offsetLeft)?0:e.offsetLeft,r.left+=isNaN(n)?0:n,r.top+=isNaN(e.offsetTop)?0:e.offsetTop,r.top+=isNaN(i)?0:i,e=e.offsetParent}return r},l=function(e){return(e.indexOf("?")>=0?"&":"?")+"nocache="+(new Date).getTime()},c=function(e){var t=[];return e.trustedDomains&&("string"==typeof e.trustedDomains?t.push("trustedDomain="+e.trustedDomains):t.push("trustedDomain="+e.trustedDomains.join(","))),t.join("&")},u=function(e,t){if(t.indexOf)return t.indexOf(e);for(var r=0,a=t.length;a>r;r++)if(t[r]===e)return r;return-1},d=function(e){if("string"==typeof e)throw new TypeError("ZeroClipboard doesn't accept query strings.");return e.length?e:[e]},h=function(e,t){if(e&&(h.prototype._singleton||this).glue(e),h.prototype._singleton)return h.prototype._singleton;h.prototype._singleton=this,this.options={};for(var r in f)this.options[r]=f[r];for(var a in t)this.options[a]=t[a];this.handlers={},h.detectFlashSupport()&&m()},p=[];h.prototype.setCurrent=function(r){e=r,this.reposition(),r.getAttribute("title")&&this.setTitle(r.getAttribute("title")),this.setHandCursor("pointer"==t(r,"cursor"))},h.prototype.setText=function(e){e&&""!==e&&(this.options.text=e,this.ready()&&this.flashBridge.setText(e))},h.prototype.setTitle=function(e){e&&""!==e&&this.htmlBridge.setAttribute("title",e)},h.prototype.setSize=function(e,t){this.ready()&&this.flashBridge.setSize(e,t)},h.prototype.setHandCursor=function(e){this.ready()&&this.flashBridge.setHandCursor(e)},h.version="1.1.7";var f={moviePath:"ZeroClipboard.swf",trustedDomains:null,text:null,hoverClass:"zeroclipboard-is-hover",activeClass:"zeroclipboard-is-active",allowScriptAccess:"sameDomain"};h.setDefaults=function(e){for(var t in e)f[t]=e[t]},h.destroy=function(){h.prototype._singleton.unglue(p);var e=h.prototype._singleton.htmlBridge;e.parentNode.removeChild(e),delete h.prototype._singleton},h.detectFlashSupport=function(){var e=!1;try{new ActiveXObject("ShockwaveFlash.ShockwaveFlash")&&(e=!0)}catch(t){navigator.mimeTypes["application/x-shockwave-flash"]&&(e=!0)}return e};var m=function(){var e=h.prototype._singleton,t=document.getElementById("global-zeroclipboard-html-bridge");if(!t){var r=' ';t=document.createElement("div"),t.id="global-zeroclipboard-html-bridge",t.setAttribute("class","global-zeroclipboard-container"),t.setAttribute("data-clipboard-ready",!1),t.style.position="absolute",t.style.left="-9999px",t.style.top="-9999px",t.style.width="15px",t.style.height="15px",t.style.zIndex="9999",t.innerHTML=r,document.body.appendChild(t)}e.htmlBridge=t,e.flashBridge=document["global-zeroclipboard-flash-bridge"]||t.children[0].lastElementChild};h.prototype.resetBridge=function(){this.htmlBridge.style.left="-9999px",this.htmlBridge.style.top="-9999px",this.htmlBridge.removeAttribute("title"),this.htmlBridge.removeAttribute("data-clipboard-text"),o(e,this.options.activeClass),e=null,this.options.text=null},h.prototype.ready=function(){var e=this.htmlBridge.getAttribute("data-clipboard-ready");return"true"===e||e===!0},h.prototype.reposition=function(){if(!e)return!1;var t=s(e),r=$(e).hasClass("pullright")?$(".form-horizontal").scrollTop():0;this.htmlBridge.style.top=t.top-r+"px",this.htmlBridge.style.left=t.left+"px",this.htmlBridge.style.width=t.width+"px",this.htmlBridge.style.height=t.height+"px",this.htmlBridge.style.zIndex=t.zIndex+1,this.setSize(t.width,t.height)},h.dispatch=function(e,t){h.prototype._singleton.receiveEvent(e,t)},h.prototype.on=function(e,t){for(var r=(""+e).split(/\s/g),a=0;r.length>a;a++)e=r[a].toLowerCase().replace(/^on/,""),this.handlers[e]||(this.handlers[e]=t);this.handlers.noflash&&!h.detectFlashSupport()&&this.receiveEvent("onNoFlash",null)},h.prototype.addEventListener=h.prototype.on,h.prototype.off=function(e,t){for(var r=(""+e).split(/\s/g),a=0;r.length>a;a++){e=r[a].toLowerCase().replace(/^on/,"");for(var n in this.handlers)n===e&&this.handlers[n]===t&&delete this.handlers[n]}},h.prototype.removeEventListener=h.prototype.off,h.prototype.receiveEvent=function(t,r){t=(""+t).toLowerCase().replace(/^on/,"");var a=e;switch(t){case"load":if(r&&10>parseFloat(r.flashVersion.replace(",",".").replace(/[^0-9\.]/gi,"")))return this.receiveEvent("onWrongFlash",{flashVersion:r.flashVersion}),void 0;this.htmlBridge.setAttribute("data-clipboard-ready",!0);break;case"mouseover":i(a,this.options.hoverClass);break;case"mouseout":o(a,this.options.hoverClass),this.resetBridge();break;case"mousedown":i(a,this.options.activeClass);break;case"mouseup":o(a,this.options.activeClass);break;case"datarequested":var n=a.getAttribute("data-clipboard-target"),s=n?document.getElementById(n):null;if(s){var l=s.value||s.textContent||s.innerText;l&&this.setText(l)}else{var c=a.getAttribute("data-clipboard-text");c&&this.setText(c)}break;case"complete":this.options.text=null}if(this.handlers[t]){var u=this.handlers[t];"function"==typeof u?u.call(a,this,r):"string"==typeof u&&window[u].call(a,this,r)}},h.prototype.glue=function(e){e=d(e);for(var t=0;e.length>t;t++)-1==u(e[t],p)&&(p.push(e[t]),a(e[t],"mouseover",r))},h.prototype.unglue=function(e){e=d(e);for(var t=0;e.length>t;t++){n(e[t],"mouseover",r);var a=u(e[t],p);-1!=a&&p.splice(a,1)}},"undefined"!=typeof module?module.exports=h:"function"==typeof define&&define.amd?define(function(){return h}):window.ZeroClipboard=h}(),function(e){var t=e.Preview||{};e.vars.previewDefaults={showAdvancedOptions:!1,includeKalturaLinks:!e.vars.ignore_seo_links,includeSeoMetadata:!e.vars.ignore_entry_seo,deliveryType:e.vars.default_delivery_type,embedType:e.vars.default_embed_code_type,secureEmbed:e.vars.embed_code_protocol_https},"https:"==window.location.protocol&&(e.vars.previewDefaults.secureEmbed=!0),t.storageName="previewDefaults",t.el="#previewModal",t.iframeContainer="previewIframe",t.ignoreChangeEvents=!0,t.getGenerator=function(){return this.generator||(this.generator=new kEmbedCodeGenerator({host:e.vars.embed_host,securedHost:e.vars.embed_host_https,partnerId:e.vars.partner_id,includeKalturaLinks:e.vars.previewDefaults.includeKalturaLinks})),this.generator},t.clipboard=new ZeroClipboard($(".copy-code"),{moviePath:"/lib/flash/ZeroClipboard.swf",trustedDomains:["*"],allowScriptAccess:"always"}),t.clipboard.on("complete",function(){var e=$(this);$("#"+e.data("clipboard-target")).select(),e.data("close")===!0&&t.closeModal(t.el)}),t.objectToArray=function(e){var t=[];for(var r in e)e[r].id=r,t.push(e[r]);return t},t.getObjectById=function(e,t){var r=$.grep(t,function(t){return t.id==e});return r.length?r[0]:!1},t.getDefault=function(r){var a=localStorage.getItem(t.storageName);return a=a?JSON.parse(a):e.vars.previewDefaults,void 0!==a[r]?a[r]:null},t.savePreviewState=function(){var e=this.Service,r={embedType:e.get("embedType"),secureEmbed:e.get("secureEmbed"),includeSeoMetadata:e.get("includeSeo"),deliveryType:e.get("deliveryType").id,showAdvancedOptions:e.get("showAdvancedOptions")};localStorage.setItem(t.storageName,JSON.stringify(r))},t.getDeliveryTypeFlashVars=function(e){if(!e)return{};var t=e.flashvars?e.flashvars:{},r=$.extend({},t);return e.streamerType&&(r.streamerType=e.streamerType),e.mediaProtocol&&(r.mediaProtocol=e.mediaProtocol),r},t.getPreviewTitle=function(e){return e.entryMeta&&e.entryMeta.name?"Embedding: "+e.entryMeta.name:e.playlistName?"Playlist: "+e.playlistName:e.playerOnly?"Player Name:"+e.name:void 0},t.openPreviewEmbed=function(t,r){var a=this,n=a.el;this.ignoreChangeEvents=!1;var i={entryId:null,entryMeta:{},playlistId:null,playlistName:null,previewOnly:null,liveBitrates:null,playerOnly:!1,uiConfId:null,name:null};t=$.extend({},i,t),r.disableEvents(),t.liveBitrates?(r.set("live",!0),r.setDeliveryType("auto")):r.set("live",!1),r.updatePlayers(t),r.enableEvents(),r.set(t);var o=this.getPreviewTitle(t),s=$(n);s.find(".title h2").text(o).attr("title",o),s.find(".close").unbind("click").click(function(){a.closeModal(n)});var l=$("body").height()-173;s.find(".content").height(l),e.layout.modal.show(n,!1)},t.closeModal=function(t){this.savePreviewState(),this.emptyDiv(this.iframeContainer),$(t).fadeOut(300,function(){e.layout.overlay.hide(),e.utils.hideFlash()})},t.emptyDiv=function(e){var t=$("#"+e),r=$("#previewIframe iframe");if(r.length)try{var a=$(r[0].contentWindow.document);a.find("#framePlayerContainer").empty()}catch(n){}return t.length?(t.empty(),t[0]):!1},t.hasIframe=function(){return $("#"+this.iframeContainer+" iframe").length},t.getCacheSt=function(){var e=new Date;return Math.floor(e.getTime()/1e3)+900},t.generateIframe=function(e){var t=$("html").hasClass("lt-ie10"),r=navigator.userAgent.toLowerCase().indexOf("firefox")>-1,a="",n=this.emptyDiv(this.iframeContainer),i=document.createElement("iframe");if(i.frameborder="0",i.frameBorder="0",i.marginheight="0",i.marginwidth="0",i.frameborder="0",i.setAttribute("allowFullScreen",""),i.setAttribute("webkitallowfullscreen",""),i.setAttribute("mozallowfullscreen",""),n.appendChild(i),t||r)i.src=this.getPreviewUrl(this.Service,!0);else{var o=i.contentDocument;o.open(),o.write(""+a+'
'+e+"
"),o.close()}},t.getEmbedProtocol=function(e,t){return t===!0?location.protocol.substring(0,location.protocol.length-1):e.get("secureEmbed")?"https":"http"},t.getEmbedFlashVars=function(t,r){var a=this.getEmbedProtocol(t,r),n=t.get("player"),i=this.getDeliveryTypeFlashVars(t.get("deliveryType"));r===!0&&(i.ks=e.vars.ks,1==t.get("live")&&(i.disableEntryRedirect=!0),i.liveAnalytics={plugin:"false",relativeTo:"PlayerHolder",position:"after",loadingPolicy:"onDemand"});var o=t.get("playlistId");if(o){var s=e.functions.getVersionFromPath(n.html5Url),l=e.functions.versionIsAtLeast(e.vars.min_kdp_version_for_playlist_api_v3,n.swf_version),c=e.functions.versionIsAtLeast(e.vars.min_html5_version_for_playlist_api_v3,s);l&&c?i["playlistAPI.kpl0Id"]=o:(i["playlistAPI.autoInsert"]="true",i["playlistAPI.kpl0Name"]=t.get("playlistName"),i["playlistAPI.kpl0Url"]=a+"://"+e.vars.api_host+"/index.php/partnerservices2/executeplaylist?"+"partner_id="+e.vars.partner_id+"&subp_id="+e.vars.partner_id+"00"+"&format=8&ks={ks}&playlist_id="+o)}return i},t.getEmbedCode=function(e,t){var r=e.get("player");if(!r||!e.get("embedType"))return"";var a=this.getCacheSt(),n={protocol:this.getEmbedProtocol(e,t),embedType:e.get("embedType"),uiConfId:r.id,width:r.width,height:r.height,entryMeta:e.get("entryMeta"),includeSeoMetadata:e.get("includeSeo"),playerId:"kaltura_player_"+a,cacheSt:a,flashVars:this.getEmbedFlashVars(e,t)};e.get("entryId")&&(n.entryId=e.get("entryId"));var i=this.getGenerator().getCode(n);return i},t.getPreviewUrl=function(t,r){var a=t.get("player");if(!a||!t.get("embedType"))return"";var n=this.getEmbedProtocol(t,r),i=n+"://"+e.vars.api_host+"/index.php/extwidget/preview";return i+="/partner_id/"+e.vars.partner_id,i+="/uiconf_id/"+a.id,t.get("entryId")&&(i+="/entry_id/"+t.get("entryId")),i+="/embed/"+t.get("embedType"),i+="?"+e.functions.flashVarsToUrl(this.getEmbedFlashVars(t,r)),r===!0&&(i+="&framed=true"),i},t.generateQrCode=function(e){var t=$("#qrcode").empty();e&&($("html").hasClass("lt-ie9")||t.qrcode({width:80,height:80,text:e}))},t.generateShortUrl=function(t,r){t&&e.client.createShortURL(t,r)},e.Preview=t}(window.kmc);var kmcApp=angular.module("kmcApp",["pascalprecht.translate"]);kmcApp.config(["$translateProvider",function(e){e.useStaticFilesLoader({prefix:"/locales/locale-",suffix:".json"});var t="en";"unknown"!=typeof localStorage&&localStorage.lang!==void 0&&(t=localStorage.lang),t.length>2&&(t=t.toLowerCase().substr(0,2)),e.preferredLanguage(t)}]),kmcApp.factory("previewService",["$rootScope",function(e){var t={},r=0;return{get:function(e){return void 0===e?t:t[e]},set:function(a,n,i){"object"==typeof a?angular.extend(t,a):t[a]=n,i||0!==r||e.$broadcast("previewChanged")},enableEvents:function(){r--},disableEvents:function(){r++},updatePlayers:function(t){e.$broadcast("playersUpdated",t)},changePlayer:function(t){e.$broadcast("changePlayer",t)},setDeliveryType:function(t){e.$broadcast("changeDelivery",t)}}}]),kmcApp.directive("showSlide",function(){return{restrict:"A",link:function(e,t,r){r.showSlide,e.$watch(r.showSlide,function(e){e&&!t.is(":visible")?t.slideDown():t.slideUp()})}}}),kmcApp.controller("PreviewCtrl",["$scope","$translate","previewService",function(e,t,r){var a=function(){e.$$phase||e.$apply()},n=kmc.Preview;n.playlistMode=!1,n.Service=r;var i=function(t){t=t||{};var r=t.uiConfId?t.uiConfId:void 0;if(kmc.vars.playlists_list||kmc.vars.players_list){if(t.playlistId||t.playerOnly){if(e.players=kmc.vars.playlists_list,!n.playlistMode)return n.playlistMode=!0,e.$broadcast("changePlayer",r),void 0}else if(e.players=kmc.vars.players_list,n.playlistMode||!e.player)return n.playlistMode=!1,e.$broadcast("changePlayer",r),void 0;r&&e.$broadcast("changePlayer",r)}},o=function(t){r.setDeliveryType("auto");var a=n.objectToArray(kmc.vars.delivery_types),i=e.deliveryType||n.getDefault("deliveryType"),o=[];$.each(a,function(){return this.minVersion&&!kmc.functions.versionIsAtLeast(this.minVersion,t.swf_version)?(this.id==i&&(i=null),!0):(o.push(this),void 0)}),e.deliveryTypes=o,i||(i=e.deliveryTypes[0].id),r.setDeliveryType(i)},s=function(t){var r=n.objectToArray(kmc.vars.embed_code_types),a=e.embedType||n.getDefault("embedType"),i=[];$.each(r,function(){if(n.playlistMode&&this.entryOnly)return this.id==a&&(a=null),!0;var e=kmc.functions.getVersionFromPath(t.html5Url);return this.minVersion&&!kmc.functions.versionIsAtLeast(this.minVersion,e)||("latest"==e||"2"==e[0])&&"legacy"==this.id?(this.id==a&&(a=null),!0):(i.push(this),void 0)}),e.embedTypes=i,a||(a=e.embedTypes[0].id),e.embedType=a};e.players=[],e.player=null,e.deliveryTypes=[],e.deliveryType=null,e.embedTypes=[],e.embedType=null,e.secureEmbed=n.getDefault("secureEmbed"),e.includeSeo=n.getDefault("includeSeoMetadata"),e.previewOnly=null,e.playerOnly=!1,e.liveBitrates=!1,e.showAdvancedOptionsStatus=n.getDefault("showAdvancedOptions"),e.shortLinkGenerated=!1,e.$on("playersUpdated",function(e,t){i(t)}),e.$on("changePlayer",function(t,r){(r||void 0===r&&e.players&&e.players.length)&&(r=r?r:e.players[0].id,e.player=r,a())}),e.$on("changeDelivery",function(t,r){e.deliveryType=r,a()}),e.showAdvancedOptions=function(t,a){t.preventDefault(),r.set("showAdvancedOptions",a,!0),e.showAdvancedOptionsStatus=a -},e.$watch("showAdvancedOptionsStatus",function(){n.clipboard.reposition()}),e.$watch("player",function(){var t=n.getObjectById(e.player,e.players);t&&(r.disableEvents(),o(t),s(t),setTimeout(function(){r.enableEvents(),r.set("player",t)},0))}),e.$watch("deliveryType",function(){var t=n.getObjectById(e.deliveryType,e.deliveryTypes);r.set("deliveryType",t),"hds"===t.id&&(e.secureEmbed=!1)}),e.$watch("embedType",function(){r.set("embedType",e.embedType)}),e.$watch("secureEmbed",function(){r.set("secureEmbed",e.secureEmbed)}),e.$watch("includeSeo",function(){r.set("includeSeo",e.includeSeo)}),e.$watch("embedCodePreview",function(){n.generateIframe(e.embedCodePreview)}),e.$watch("previewOnly",function(){e.closeButtonText=e.previewOnly?t("CLOSE"):t("COPY_AND_CLOSE"),a()}),e.$on("previewChanged",function(){if(!n.ignoreChangeEvents){var i=n.getPreviewUrl(r);e.embedCode=n.getEmbedCode(r),e.embedCodePreview=n.getEmbedCode(r,!0),e.previewOnly=r.get("previewOnly"),e.playerOnly=r.get("playerOnly"),e.liveBitrates=r.get("liveBitrates"),a(),n.hasIframe()||n.generateIframe(e.embedCodePreview),e.previewUrl=t("UPDATING"),e.shortLinkGenerated=!1,n.generateShortUrl(i,function(t){t||(t=i),e.shortLinkGenerated=!0,e.previewUrl=t,n.generateQrCode(t),a()})}})}]),0==kmc.vars.allowFrame&&top!=window&&(top.location=window.location),kmc.vars.debug=!1,kmc.vars.quickstart_guide="/content/docs/pdf/KMC_User_Manual.pdf",kmc.vars.help_url=kmc.vars.service_url+"/kmc5help.html",kmc.vars.port=window.location.port?":"+window.location.port:"",kmc.vars.base_host=window.location.hostname+kmc.vars.port,kmc.vars.base_url=window.location.protocol+"//"+kmc.vars.base_host,kmc.vars.api_host=kmc.vars.host,kmc.vars.api_url=window.location.protocol+"//"+kmc.vars.api_host,kmc.vars.min_kdp_version_for_playlist_api_v3="3.6.15",kmc.vars.min_html5_version_for_playlist_api_v3="1.7.1.3",kmc.log=function(){if(kmc.vars.debug&&"undefined"!=typeof console&&console.log)if(1==arguments.length)console.log(arguments[0]);else{var e=Array.prototype.slice.call(arguments);console.log(e[0],e.slice(1))}},kmc.functions={loadSwf:function(e){var t=window.location.protocol+"//"+kmc.vars.cdn_host+"/flash/kmc/"+kmc.vars.kmc_version+"/kmc.swf",r={kmc_uiconf:kmc.vars.kmc_general_uiconf,permission_uiconf:kmc.vars.kmc_permissions_uiconf,host:kmc.vars.host,cdnhost:kmc.vars.cdn_host,srvurl:"api_v3/index.php",protocol:window.location.protocol+"//",partnerid:kmc.vars.partner_id,subpid:kmc.vars.partner_id+"00",ks:kmc.vars.ks,entryId:"-1",kshowId:"-1",debugmode:"true",widget_id:"_"+kmc.vars.partner_id,urchinNumber:kmc.vars.google_analytics_account,firstLogin:kmc.vars.first_login,openPlayer:"kmc.preview_embed.doPreviewEmbed",openPlaylist:"kmc.preview_embed.doPreviewEmbed",openCw:"kmc.functions.openKcw",maxUploadSize:"2047",language:e};kmc.vars.disable_analytics&&(r.disableAnalytics=!0);var a={allowNetworking:"all",allowScriptAccess:"always"};swfobject.embedSWF(t,"kcms","100%","100%","10.0.0",!1,r,a),$("#kcms").attr("style","")},checkForOngoingProcess:function(){var e;try{e=$("#kcms")[0].hasOngoingProcess()}catch(t){e=null}return null!==e?e:void 0},expired:function(){kmc.user.logout()},openKcw:function(e,t){e=e||"";var r="uploadWebCam"==t?kmc.vars.kcw_webcam_uiconf:kmc.vars.kcw_import_uiconf,a={host:kmc.vars.host,cdnhost:kmc.vars.cdn_host,protocol:window.location.protocol.slice(0,-1),partnerid:kmc.vars.partner_id,subPartnerId:kmc.vars.partner_id+"00",sessionId:kmc.vars.ks,devFlag:"true",entryId:"-1",kshow_id:"-1",terms_of_use:kmc.vars.terms_of_use,close:"kmc.functions.onCloseKcw",quick_edit:0,kvar_conversionQuality:e},n={allowscriptaccess:"always",allownetworking:"all",bgcolor:"#DBE3E9",quality:"high",movie:kmc.vars.service_url+"/kcw/ui_conf_id/"+r};kmc.layout.modal.open({width:700,height:420,content:'
'}),swfobject.embedSWF(n.movie,"kcw","680","400","9.0.0",!1,a,n)},onCloseKcw:function(){kmc.layout.modal.close(),$("#kcms")[0].gotoPage({moduleName:"content",subtab:"manage"})},openChangePwd:function(){kmc.user.changeSetting("password")},openChangeEmail:function(){kmc.user.changeSetting("email")},openChangeName:function(){kmc.user.changeSetting("name")},getAddPanelPosition:function(){var e=$("#add").parent();return e.position().left+e.width()-10},openClipApp:function(e,t){var r=kmc.vars.base_url+"/apps/clipapp/"+kmc.vars.clipapp.version;r+="/?kdpUiconf="+kmc.vars.clipapp.kdp+"&kclipUiconf="+kmc.vars.clipapp.kclip,r+="&partnerId="+kmc.vars.partner_id+"&host="+kmc.vars.host+"&mode="+t+"&config=kmc&entryId="+e;var a="trim"==t?"Trimming Tool":"Clipping Tool";kmc.layout.modal.open({width:950,height:616,title:a,content:'',className:"iframe",closeCallback:function(){$("#kcms")[0].gotoPage({moduleName:"content",subtab:"manage"})}})},openStudio:function(){return kmc.utils.hideFlash(!0),kmc.utils.openIframe(kmc.vars.base_url+"/apps/studio/"+kmc.vars.studio.version+"/index.html"),!1},openLiveAnalytics:function(){return kmc.utils.hideFlash(!0),kmc.utils.openIframe(kmc.vars.base_url+"/apps/liveanalytics/"+kmc.vars.liveanalytics.version+"/index.html"),!1},openLiveAnalyticsDrilldown:function(e,t){var r=t?t:"",a=kmc.vars.base_url+"/apps/liveanalytics/"+kmc.vars.liveanalytics.version+"/index.html#/entry/"+e+"/nonav",n='';kmc.layout.modal.open({width:1040,height:"90%",title:r,content:n,contentHeight:"94%"})},openLiveDashboard:function(e){var t="Live Dashboard";kmc.vars.liveDashboard.entryId=e;var r=kmc.vars.base_url+"/apps/liveDashboard/"+kmc.vars.liveDashboard.version+"/index.html",a='';kmc.layout.modal.open({width:1050,height:695,title:t,content:a,contentHeight:"94%"})},openUsageDashboard:function(){return kmc.utils.hideFlash(!0),kmc.utils.openIframe(kmc.vars.base_url+"/apps/usage-dashboard/"+kmc.vars.usagedashboard.version+"/index.html"),!1},flashVarsToUrl:function(e){var t="";for(var r in e){var a="object"==typeof e[r]?JSON.stringify(e[r]):e[r];t+="&flashvars["+encodeURIComponent(r)+"]="+encodeURIComponent(a)}return t},versionIsAtLeast:function(e,t){if(!t||!e)return!1;if("latest"===t)return!0;e=e.replace(/[^\d.]/g,""),t=t.replace(/[^\d.]/g,"");for(var r=e.split("."),a=t.split("."),n=0;r.length>n;n++){if(parseInt(a[n])>parseInt(r[n]))return!0;if(parseInt(a[n]) *").each(function(){e+=$(this).width()});var t=function(){kmc.vars.close_menu=!0;var t={width:0,visibility:"visible",top:"6px",right:"29px"},r={width:e+"px","padding-top":"2px","padding-bottom":"2px"};$("#user_links").css(t),$("#user_links").animate(r,500)};$("#user").hover(t).click(t),$("#user_links").mouseover(function(){kmc.vars.close_menu=!1}),$("#user_links").mouseleave(function(){kmc.vars.close_menu=!0,setTimeout(kmc.utils.closeMenu,650)}),$("#closeMenu").click(function(){kmc.vars.close_menu=!0,kmc.utils.closeMenu()})},closeMenu:function(){kmc.vars.close_menu&&$("#user_links").animate({width:0},500,function(){$("#user_links").css({width:"auto",visibility:"hidden"})})},activateHeader:function(){$("#user_links a").click(function(e){var t="A"==e.target.tagName?e.target.id:$(e.target).parent().attr("id");switch(t){case"Quickstart Guide":return this.href=kmc.vars.quickstart_guide,!0;case"Logout":return kmc.user.logout(),!1;case"Support":return kmc.user.openSupport(this),!1;case"ChangePartner":return kmc.user.changePartner(),!1}})},resize:function(){var e=$.browser.ie?640:590,t=$(window).height()-44;e>t&&(t=e),("visible"==$("#flash_wrap").css("visibility")||"inherit"==$("#flash_wrap").css("visibility"))&&($("#flash_wrap").height(t),$("#kcms").height(t)),kmc.utils.kmcHeight=t,$("#server_wrap iframe").height(t-2)},isModuleLoaded:function(){($("#flash_wrap object").length||$("#flash_wrap embed").length)&&(kmc.utils.resize(),clearInterval(kmc.vars.isLoadedInterval),kmc.vars.isLoadedInterval=null)},debug:function(){try{console.info(" ks: ",kmc.vars.ks),console.info(" partner_id: ",kmc.vars.partner_id)}catch(e){}},maskHeader:function(e){e?$("#mask").hide():$("#mask").show()},createTabs:function(e){if($("#closeMenu").trigger("click"),e){for(var t,r=kmc.vars.service_url+"/index.php/kmc/kmc4",a=e.length,n="",i=0;a>i;i++)t="action"==e[i].type?'class="menu" ':"",("fr_FR"==localStorage.lang||"ja_JP"==localStorage.lang)&&(t=""),n+='
  • '+e[i].display_name+"
  • ";$("#hTabs").html(n);var o=$("body").width()-($("#logo").width()+$("#hTabs").width()+100);$("#user").width()+20>o&&$("#user").width(o),$("#hTabs a").click(function(e){if(window.studioDataChanged===!0){var t=confirm("You are about to leave this page without saving.\nContinue?");if(t!==!0)return e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation(),void 0;window.studioDataChanged=!1}var r="A"==e.target.tagName?e.target.id:$(e.target).parent().attr("id"),a="A"==e.target.tagName?$(e.target).attr("rel"):$(e.target).parent().attr("rel"),n={moduleName:r,subtab:a};return kmc.utils.verifyUploadVisible(n.moduleName)||$("#kcms")[0].gotoPage(n),!1})}else alert("Error getting tabs")},verifyUploadVisible:function(e){if("add"==e&&"block"==$("#server_wrap").css("display")){var t=confirm("Close this page to upload files.\nClose now?");return 1==t&&($("#kcms")[0].gotoPage({moduleName:"content",subtab:"manage"}),$("#kcms")[0].gotoPage({moduleName:"add"})),!0}return!1},setTab:function(e,t){t&&$("#kmcHeader ul li a").removeClass("active"),$("a#"+e).addClass("active")},resetTab:function(e){$("a#"+e).removeClass("active")},kmcHeight:$("#flash_wrap").height(),hideFlash:function(e){var t=$("html").hasClass("lt-ie9");e?t?$("#flash_wrap").css("margin-right","3333px"):($("#flash_wrap").css("visibility","hidden"),$("#flash_wrap").height()>0&&(this.kmcHeight=$("#flash_wrap").height()),$("#flash_wrap").height(0)):t?$("#flash_wrap").css("margin-right","0"):($("#flash_wrap").css("visibility","visible"),$("#flash_wrap").height(this.kmcHeight))},showFlash:function(){if($("#server_wrap").hide(),$("#server_frame").removeAttr("src"),!kmc.layout.modal.isOpen()){$("#flash_wrap").css("visibility","visible"),this.kmcHeight>0&&$("#flash_wrap").height(this.kmcHeight);var e=$("html").hasClass("lt-ie9");e&&$("#flash_wrap").css("margin-right","0")}$("#server_wrap").css("margin-top",0)},openIframe:function(e){$("#server_frame").attr("src",e),$("#server_wrap").css("margin-top","-"+($("#flash_wrap").height()+2)+"px"),$("#server_wrap").show()},openHelp:function(e){$("#kcms")[0].doHelp(e)},setClientIP:function(){kmc.vars.clientIP="",kmc.vars.akamaiEdgeServerIpURL&&$.ajax({url:window.location.protocol+"//"+kmc.vars.akamaiEdgeServerIpURL,crossDomain:!0,success:function(e){kmc.vars.clientIP=$(e).find("serverip").text()}})},getClientIP:function(){return kmc.vars.clientIP}},kmc.mediator={writeUrlHash:function(e,t){location.hash=e+"|"+t,document.title="KMC > "+e+(t&&""!==t?" > "+t+" |":"")},readUrlHash:function(){var e,t,r="dashboard",a="",n={};try{e=location.hash.split("#")[1].split("|")}catch(i){t=!0}if(!t&&""!==e[0]){if(r=e[0],a=e[1],e[2])for(var o=e[2].split("&"),s=0;o.length>s;s++){var l=o[s].split(":");n[l[0]]=l[1]}switch(r){case"content":switch(a){case"Moderate":a="moderation";break;case"Syndicate":a="syndication"}a=a.toLowerCase();break;case"appstudio":r="studio",a="playersList";break;case"Settings":switch(r="account",a){case"Account_Settings":a="overview";break;case"Integration Settings":a="integration";break;case"Access Control":a="accessControl";break;case"Transcoding Settings":a="transcoding";break;case"Account Upgrade":a="upgrade"}break;case"reports":r="analytics","Bandwidth Usage Reports"==a&&(a="usageTabTitle")}}return{moduleName:r,subtab:a,extra:n}}},kmc.preview_embed={doPreviewEmbed:function(e,t,r,a,n,i,o,s,l){var c={previewOnly:a};i&&(c.uiConfId=parseInt(i)),n?"multitab_playlist"==e?(c.playerOnly=!0,c.name=unescape(t)):(c.playlistId=e,c.playlistName=unescape(t)):(c.entryId=e,c.entryMeta={name:unescape(t),description:unescape(r),duration:s,thumbnailUrl:l},o&&(c.liveBitrates=o)),kmc.Preview.openPreviewEmbed(c,kmc.Preview.Service)},doFlavorPreview:function(e,t,r){var a=kmc.vars.default_kdp,n=kmc.Preview.getGenerator().getCode({protocol:location.protocol.substring(0,location.protocol.length-1),embedType:"legacy",entryId:e,uiConfId:parseInt(a.id),width:a.width,height:a.height,includeSeoMetadata:!1,includeHtml5Library:!1,flashVars:{ks:kmc.vars.ks,flavorId:r.asset_id}}),i='
    '+n+"
    "+"
    Entry Name:
     "+unescape(t)+"
    "+"
    Entry Id:
     "+e+"
    "+"
    Flavor Name:
     "+r.flavor_name+"
    "+"
    Flavor Asset Id:
     "+r.asset_id+"
    "+"
    Bitrate:
     "+r.bitrate+"
    "+"
    Codec:
     "+r.codec+"
    "+"
    Dimensions:
     "+r.dimensions.width+" x "+r.dimensions.height+"
    "+"
    Format:
     "+r.format+"
    "+"
    Size (KB):
     "+r.sizeKB+"
    "+"
    Status:
     "+r.status+"
    "+"
    ";kmc.layout.modal.open({width:parseInt(a.width)+120,height:parseInt(a.height)+300,title:"Flavor Preview",content:'
    '+i+"
    "})},updateList:function(e){var t=e?"playlist":"player";$.ajax({url:kmc.vars.base_url+kmc.vars.getuiconfs_url,type:"POST",data:{type:t,partner_id:kmc.vars.partner_id,ks:kmc.vars.ks},dataType:"json",success:function(t){t&&t.length&&(t.sort(function(e,t){return e.updatedAt>t.updatedAt?-1:e.updatedAti;i++){var o=r[i].split("|");t[o[0]]=o[1]}return t},s=function(e){e=o(e);var t="";for(var r in e){var a=e[r];t+=a+r}return md5(t)},l=s(r);n+="&kalsig="+l,$.ajax({type:"GET",url:n,dataType:"jsonp",data:r,cache:!1,success:a})},createShortURL:function(e,t){kmc.log("createShortURL");var r={"shortLink:objectType":"KalturaShortLink","shortLink:systemName":"KMC-PREVIEW","shortLink:fullUrl":e};kmc.client.makeRequest("shortlink_shortlink","add",r,function(e){var r=!1;t?(e.id&&(r=kmc.vars.service_url+"/tiny/"+e.id),t(r)):kmc.preview_embed.setShortURL(e.id)})}},kmc.layout={init:function(){$("#kmcHeader").bind("click",function(){$("#hTabs a").each(function(e,t){var r=$(t);return r.hasClass("menu")&&r.hasClass("active")?($("#kcms")[0].gotoPage({moduleName:r.attr("id"),subtab:r.attr("rel")}),void 0):!0})}),$("body").append('
    ')},overlay:{show:function(){$("#overlay").show()},hide:function(){$("#overlay").hide()}},modal:{el:"#modal",create:function(e){var t={el:kmc.layout.modal.el,title:"",content:"",help:"",width:680,height:"auto",className:"",contentHeight:"auto"};$.extend(t,e);var r=$(t.el),a=r.find(".title h2"),n=r.find(".content");return n.height(t.contentHeight),t.className="modal "+t.className,r.css({width:t.width,height:t.height}).attr("class",t.className),t.title?a.text(t.title).attr("title",t.title).parent().show():(a.parent().hide(),n.addClass("flash_only")),r.find(".help").remove(),a.parent().append(t.help),n[0].innerHTML=t.content,r.find(".close").click(function(){kmc.layout.modal.close(t.el),$.isFunction(e.closeCallback)&&e.closeCallback()}),r},show:function(e,t){t=void 0===t?!0:t,e=e||kmc.layout.modal.el;var r=$(e);kmc.utils.hideFlash(!0),kmc.layout.overlay.show(),r.fadeIn(600),$.browser.msie||r.css("display","block"),t&&this.position(e)},open:function(e){this.create(e);var t=e.el||kmc.layout.modal.el;this.show(t)},position:function(e){e=e||kmc.layout.modal.el;var t=$(e),r=($(window).height()-t.height())/2,a=($(window).width()-t.width())/(2+$(window).scrollLeft());r=40>r?40:r,t.css({top:r+"px",left:a+"px"})},close:function(e){e=e||kmc.layout.modal.el,$(e).fadeOut(300,function(){$(e).find(".content").html(""),kmc.layout.overlay.hide(),kmc.utils.hideFlash()})},isOpen:function(e){return e=e||kmc.layout.modal.el,$(e).is(":visible")}}},kmc.user={openSupport:function(e){var t=e.href;this.kmcHeight=$("#flash_wrap").height(),kmc.utils.hideFlash(!0),kmc.layout.overlay.show();var r='';kmc.layout.modal.create({width:550,title:"Support Request",content:r}),$("#support").load(function(){kmc.layout.modal.show(),kmc.vars.support_frame_height||(kmc.vars.support_frame_height=$("#support")[0].contentWindow.document.body.scrollHeight),$("#support").height(kmc.vars.support_frame_height),kmc.layout.modal.position()})},logout:function(){var e=kmc.functions.checkForOngoingProcess();if(e)return alert(e),!1;var t=kmc.mediator.readUrlHash();$.ajax({url:kmc.vars.base_url+"/index.php/kmc/logout",type:"POST",data:{ks:kmc.vars.ks},dataType:"json",complete:function(){window.location=kmc.vars.logoutUrl?kmc.vars.logoutUrl:kmc.vars.service_url+"/index.php/kmc/kmc#"+t.moduleName+"|"+t.subtab}})},changeSetting:function(e){var t,r;switch(e){case"password":t="Change Password",r=180;break;case"email":t="Change Email Address",r=160;break;case"name":t="Edit Name",r=200}var a=kmc.vars.kmc_secured||"https:"==location.protocol?"https":"http",n=a+"://"+window.location.hostname,i=n+kmc.vars.port+"/index.php/kmc/updateLoginData/type/"+e;i=i+"?parent="+encodeURIComponent(document.location.href);var o='';kmc.layout.modal.open({width:370,title:t,content:o}),XD.receiveMessage(function(e){kmc.layout.modal.close(),"reload"==e.data&&($.browser.msie&&8>$.browser.version&&(window.location.hash="account|user"),window.location.reload())},n)},changePartner:function(){var e,t,r,a=0,n=kmc.vars.allowed_partners.length,i='
    Please choose partner:
    ';for(e=0;n>e;e++)a=kmc.vars.allowed_partners[e].id,kmc.vars.partner_id==a?(t=' checked="checked"',r=' style="font-weight: bold"'):(t="",r=""),i+="  "+kmc.vars.allowed_partners[e].name+"";return i+='
    ',kmc.layout.modal.open({width:300,title:"Change Account",content:i}),$("#do_change_partner").click(function(){var e=kmc.vars.base_url+"/index.php/kmc/extlogin",t=$("").attr({type:"hidden",name:"ks",value:kmc.vars.ks}),r=$("").attr({type:"hidden",name:"partner_id",value:$("input[name=pid]:radio:checked").val()}),a=$("
    ").attr({action:e,method:"post",style:"display: none"}).append(t,r);$("body").append(a),a[0].submit()}),!1}},$(function(){kmc.layout.init(),kmc.utils.handleMenu(),kmc.functions.loadSwf(window.lang),$(window).wresize(kmc.utils.resize),kmc.vars.isLoadedInterval=setInterval(kmc.utils.isModuleLoaded,200),kmc.preview_embed.updateList(),kmc.preview_embed.updateList(!0),kmc.utils.setClientIP()}),$(window).resize(function(){kmc.layout.modal.isOpen()&&kmc.layout.modal.position()}),window.onbeforeunload=kmc.functions.checkForOngoingProcess,function(e){e.fn.wresize=function(t){function r(){if(e.browser.msie)if(wresize.fired){var t=parseInt(e.browser.version,10);if(wresize.fired=!1,7>t)return!1;if(7==t){var r=e(window).width();if(r!=wresize.width)return wresize.width=r,!1}}else wresize.fired=!0;return!0}function a(e){return r()?t.apply(this,[e]):void 0}return version="1.1",wresize={fired:!1,width:0},this.each(function(){this==window?e(this).resize(a):e(this).resize(t)}),this}}(jQuery);var XD=function(){var e,t,r,a=1,n=this;return{postMessage:function(e,t,r){t&&(r=r||parent,n.postMessage?r.postMessage(e,t.replace(/([^:]+:\/\/[^\/]+).*/,"$1")):t&&(r.location=t.replace(/#.*$/,"")+"#"+ +new Date+a++ +"&"+e))},receiveMessage:function(a,i){n.postMessage?(a&&(r=function(e){return"string"==typeof i&&e.origin!==i||"[object Function]"===Object.prototype.toString.call(i)&&i(e.origin)===!1?!1:(a(e),void 0)}),n.addEventListener?n[a?"addEventListener":"removeEventListener"]("message",r,!1):n[a?"attachEvent":"detachEvent"]("onmessage",r)):(e&&clearInterval(e),e=null,a&&(e=setInterval(function(){var e=document.location.hash,r=/^#?\d+&/;e!==t&&r.test(e)&&(t=e,a({data:e.replace(r,"")}))},100)))}}}(); \ No newline at end of file +},e.$watch("showAdvancedOptionsStatus",function(){n.clipboard.reposition()}),e.$watch("player",function(){var t=n.getObjectById(e.player,e.players);t&&(r.disableEvents(),o(t),s(t),setTimeout(function(){r.enableEvents(),r.set("player",t)},0))}),e.$watch("deliveryType",function(){var t=n.getObjectById(e.deliveryType,e.deliveryTypes);r.set("deliveryType",t),"hds"===t.id&&(e.secureEmbed=!1)}),e.$watch("embedType",function(){r.set("embedType",e.embedType)}),e.$watch("secureEmbed",function(){r.set("secureEmbed",e.secureEmbed)}),e.$watch("includeSeo",function(){r.set("includeSeo",e.includeSeo)}),e.$watch("embedCodePreview",function(){n.generateIframe(e.embedCodePreview)}),e.$watch("previewOnly",function(){e.closeButtonText=e.previewOnly?t("CLOSE"):t("COPY_AND_CLOSE"),a()}),e.$on("previewChanged",function(){if(!n.ignoreChangeEvents){var i=n.getPreviewUrl(r);e.embedCode=n.getEmbedCode(r),e.embedCodePreview=n.getEmbedCode(r,!0),e.previewOnly=r.get("previewOnly"),e.playerOnly=r.get("playerOnly"),e.liveBitrates=r.get("liveBitrates"),a(),n.hasIframe()||n.generateIframe(e.embedCodePreview),e.previewUrl=t("UPDATING"),e.shortLinkGenerated=!1,n.generateShortUrl(i,function(t){t||(t=i),e.shortLinkGenerated=!0,e.previewUrl=t,n.generateQrCode(t),a()})}})}]),0==kmc.vars.allowFrame&&top!=window&&(top.location=window.location),kmc.vars.debug=!1,kmc.vars.quickstart_guide="/content/docs/pdf/KMC_User_Manual.pdf",kmc.vars.help_url=kmc.vars.service_url+"/kmc5help.html",kmc.vars.port=window.location.port?":"+window.location.port:"",kmc.vars.base_host=window.location.hostname+kmc.vars.port,kmc.vars.base_url=window.location.protocol+"//"+kmc.vars.base_host,kmc.vars.api_host=kmc.vars.host,kmc.vars.api_url=window.location.protocol+"//"+kmc.vars.api_host,kmc.vars.min_kdp_version_for_playlist_api_v3="3.6.15",kmc.vars.min_html5_version_for_playlist_api_v3="1.7.1.3",kmc.log=function(){if(kmc.vars.debug&&"undefined"!=typeof console&&console.log)if(1==arguments.length)console.log(arguments[0]);else{var e=Array.prototype.slice.call(arguments);console.log(e[0],e.slice(1))}},kmc.functions={loadSwf:function(e){var t=window.location.protocol+"//"+kmc.vars.cdn_host+"/flash/kmc/"+kmc.vars.kmc_version+"/kmc.swf",r={kmc_uiconf:kmc.vars.kmc_general_uiconf,permission_uiconf:kmc.vars.kmc_permissions_uiconf,host:kmc.vars.host,cdnhost:kmc.vars.cdn_host,srvurl:"api_v3/index.php",protocol:window.location.protocol+"//",partnerid:kmc.vars.partner_id,subpid:kmc.vars.partner_id+"00",ks:kmc.vars.ks,entryId:"-1",kshowId:"-1",debugmode:"true",widget_id:"_"+kmc.vars.partner_id,urchinNumber:kmc.vars.google_analytics_account,firstLogin:kmc.vars.first_login,openPlayer:"kmc.preview_embed.doPreviewEmbed",openPlaylist:"kmc.preview_embed.doPreviewEmbed",openCw:"kmc.functions.openKcw",maxUploadSize:"2047",language:e};kmc.vars.disable_analytics&&(r.disableAnalytics=!0);var a={allowNetworking:"all",allowScriptAccess:"always"};swfobject.embedSWF(t,"kcms","100%","100%","10.0.0",!1,r,a),$("#kcms").attr("style","")},checkForOngoingProcess:function(){var e;try{e=$("#kcms")[0].hasOngoingProcess()}catch(t){e=null}return null!==e?e:void 0},expired:function(){kmc.user.logout()},openKcw:function(e,t){e=e||"";var r="uploadWebCam"==t?kmc.vars.kcw_webcam_uiconf:kmc.vars.kcw_import_uiconf,a={host:kmc.vars.host,cdnhost:kmc.vars.cdn_host,protocol:window.location.protocol.slice(0,-1),partnerid:kmc.vars.partner_id,subPartnerId:kmc.vars.partner_id+"00",sessionId:kmc.vars.ks,devFlag:"true",entryId:"-1",kshow_id:"-1",terms_of_use:kmc.vars.terms_of_use,close:"kmc.functions.onCloseKcw",quick_edit:0,kvar_conversionQuality:e},n={allowscriptaccess:"always",allownetworking:"all",bgcolor:"#DBE3E9",quality:"high",movie:kmc.vars.service_url+"/kcw/ui_conf_id/"+r};kmc.layout.modal.open({width:700,height:420,content:'
    '}),swfobject.embedSWF(n.movie,"kcw","680","400","9.0.0",!1,a,n)},onCloseKcw:function(){kmc.layout.modal.close(),$("#kcms")[0].gotoPage({moduleName:"content",subtab:"manage"})},openChangePwd:function(){kmc.user.changeSetting("password")},openChangeEmail:function(){kmc.user.changeSetting("email")},openChangeName:function(){kmc.user.changeSetting("name")},getAddPanelPosition:function(){var e=$("#add").parent();return e.position().left+e.width()-10},openClipApp:function(e,t){var r=kmc.vars.base_url+"/apps/clipapp/"+kmc.vars.clipapp.version;r+="/?kdpUiconf="+kmc.vars.clipapp.kdp+"&kclipUiconf="+kmc.vars.clipapp.kclip,r+="&partnerId="+kmc.vars.partner_id+"&host="+kmc.vars.host+"&mode="+t+"&config=kmc&entryId="+e;var a="trim"==t?"Trimming Tool":"Clipping Tool";kmc.layout.modal.open({width:950,height:616,title:a,content:'',className:"iframe",closeCallback:function(){$("#kcms")[0].gotoPage({moduleName:"content",subtab:"manage"})}})},openStudio:function(){return kmc.utils.hideFlash(!0),kmc.utils.openIframe(kmc.vars.base_url+"/apps/studio/"+kmc.vars.studio.version+"/index.html"),!1},openStudioV3:function(){return kmc.utils.hideFlash(!0),kmc.utils.openIframe(kmc.vars.base_url+"/apps/studioV3/"+kmc.vars.studioV3.version+"/index.html"),!1},openLiveAnalytics:function(){return kmc.utils.hideFlash(!0),kmc.utils.openIframe(kmc.vars.base_url+"/apps/liveanalytics/"+kmc.vars.liveanalytics.version+"/index.html"),!1},openLiveAnalyticsDrilldown:function(e,t){var r=t?t:"",a=kmc.vars.base_url+"/apps/liveanalytics/"+kmc.vars.liveanalytics.version+"/index.html#/entry/"+e+"/nonav",n='';kmc.layout.modal.open({width:1040,height:"90%",title:r,content:n,contentHeight:"94%"})},openLiveDashboard:function(e){var t="Live Dashboard";kmc.vars.liveDashboard.entryId=e;var r=kmc.vars.base_url+"/apps/liveDashboard/"+kmc.vars.liveDashboard.version+"/index.html",a='';kmc.layout.modal.open({width:1050,height:695,title:t,content:a,contentHeight:"94%"})},openUsageDashboard:function(){return kmc.utils.hideFlash(!0),kmc.utils.openIframe(kmc.vars.base_url+"/apps/usage-dashboard/"+kmc.vars.usagedashboard.version+"/index.html"),!1},flashVarsToUrl:function(e){var t="";for(var r in e){var a="object"==typeof e[r]?JSON.stringify(e[r]):e[r];t+="&flashvars["+encodeURIComponent(r)+"]="+encodeURIComponent(a)}return t},versionIsAtLeast:function(e,t){if(!t||!e)return!1;if("latest"===t)return!0;e=e.replace(/[^\d.]/g,""),t=t.replace(/[^\d.]/g,"");for(var r=e.split("."),a=t.split("."),n=0;r.length>n;n++){if(parseInt(a[n])>parseInt(r[n]))return!0;if(parseInt(a[n]) *").each(function(){e+=$(this).width()});var t=function(){kmc.vars.close_menu=!0;var t={width:0,visibility:"visible",top:"6px",right:"29px"},r={width:e+"px","padding-top":"2px","padding-bottom":"2px"};$("#user_links").css(t),$("#user_links").animate(r,500)};$("#user").hover(t).click(t),$("#user_links").mouseover(function(){kmc.vars.close_menu=!1}),$("#user_links").mouseleave(function(){kmc.vars.close_menu=!0,setTimeout(kmc.utils.closeMenu,650)}),$("#closeMenu").click(function(){kmc.vars.close_menu=!0,kmc.utils.closeMenu()})},closeMenu:function(){kmc.vars.close_menu&&$("#user_links").animate({width:0},500,function(){$("#user_links").css({width:"auto",visibility:"hidden"})})},activateHeader:function(){$("#user_links a").click(function(e){var t="A"==e.target.tagName?e.target.id:$(e.target).parent().attr("id");switch(t){case"Quickstart Guide":return this.href=kmc.vars.quickstart_guide,!0;case"Logout":return kmc.user.logout(),!1;case"Support":return kmc.user.openSupport(this),!1;case"ChangePartner":return kmc.user.changePartner(),!1}})},resize:function(){var e=$.browser.ie?640:590,t=$(window).height()-44;e>t&&(t=e),("visible"==$("#flash_wrap").css("visibility")||"inherit"==$("#flash_wrap").css("visibility"))&&($("#flash_wrap").height(t),$("#kcms").height(t)),kmc.utils.kmcHeight=t,$("#server_wrap iframe").height(t-2)},isModuleLoaded:function(){($("#flash_wrap object").length||$("#flash_wrap embed").length)&&(kmc.utils.resize(),clearInterval(kmc.vars.isLoadedInterval),kmc.vars.isLoadedInterval=null)},debug:function(){try{console.info(" ks: ",kmc.vars.ks),console.info(" partner_id: ",kmc.vars.partner_id)}catch(e){}},maskHeader:function(e){e?$("#mask").hide():$("#mask").show()},createTabs:function(e){if($("#closeMenu").trigger("click"),e){for(var t,r=kmc.vars.service_url+"/index.php/kmc/kmc4",a=e.length,n="",i=0;a>i;i++)t="action"==e[i].type?'class="menu" ':"",("fr_FR"==localStorage.lang||"ja_JP"==localStorage.lang)&&(t=""),n+='
  • '+e[i].display_name+"
  • ";$("#hTabs").html(n);var o=$("body").width()-($("#logo").width()+$("#hTabs").width()+100);$("#user").width()+20>o&&$("#user").width(o),$("#hTabs a").click(function(e){if(window.studioDataChanged===!0){var t=confirm("You are about to leave this page without saving.\nContinue?");if(t!==!0)return e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation(),void 0;window.studioDataChanged=!1}var r="A"==e.target.tagName?e.target.id:$(e.target).parent().attr("id"),a="A"==e.target.tagName?$(e.target).attr("rel"):$(e.target).parent().attr("rel"),n={moduleName:r,subtab:a};return kmc.utils.verifyUploadVisible(n.moduleName)||$("#kcms")[0].gotoPage(n),!1})}else alert("Error getting tabs")},verifyUploadVisible:function(e){if("add"==e&&"block"==$("#server_wrap").css("display")){var t=confirm("Close this page to upload files.\nClose now?");return 1==t&&($("#kcms")[0].gotoPage({moduleName:"content",subtab:"manage"}),$("#kcms")[0].gotoPage({moduleName:"add"})),!0}return!1},setTab:function(e,t){t&&$("#kmcHeader ul li a").removeClass("active"),$("a#"+e).addClass("active")},resetTab:function(e){$("a#"+e).removeClass("active")},kmcHeight:$("#flash_wrap").height(),hideFlash:function(e){var t=$("html").hasClass("lt-ie9");e?t?$("#flash_wrap").css("margin-right","3333px"):($("#flash_wrap").css("visibility","hidden"),$("#flash_wrap").height()>0&&(this.kmcHeight=$("#flash_wrap").height()),$("#flash_wrap").height(0)):t?$("#flash_wrap").css("margin-right","0"):($("#flash_wrap").css("visibility","visible"),$("#flash_wrap").height(this.kmcHeight))},showFlash:function(){if($("#server_wrap").hide(),$("#server_frame").removeAttr("src"),!kmc.layout.modal.isOpen()){$("#flash_wrap").css("visibility","visible"),this.kmcHeight>0&&$("#flash_wrap").height(this.kmcHeight);var e=$("html").hasClass("lt-ie9");e&&$("#flash_wrap").css("margin-right","0")}$("#server_wrap").css("margin-top",0)},openIframe:function(e){$("#server_frame").attr("src",e),$("#server_wrap").css("margin-top","-"+($("#flash_wrap").height()+2)+"px"),$("#server_wrap").show()},openHelp:function(e){$("#kcms")[0].doHelp(e)},setClientIP:function(){kmc.vars.clientIP="",kmc.vars.akamaiEdgeServerIpURL&&$.ajax({url:window.location.protocol+"//"+kmc.vars.akamaiEdgeServerIpURL,crossDomain:!0,success:function(e){kmc.vars.clientIP=$(e).find("serverip").text()}})},getClientIP:function(){return kmc.vars.clientIP}},kmc.mediator={writeUrlHash:function(e,t){location.hash=e+"|"+t,document.title="KMC > "+e+(t&&""!==t?" > "+t+" |":"")},readUrlHash:function(){var e,t,r="dashboard",a="",n={};try{e=location.hash.split("#")[1].split("|")}catch(i){t=!0}if(!t&&""!==e[0]){if(r=e[0],a=e[1],e[2])for(var o=e[2].split("&"),s=0;o.length>s;s++){var l=o[s].split(":");n[l[0]]=l[1]}switch(r){case"content":switch(a){case"Moderate":a="moderation";break;case"Syndicate":a="syndication"}a=a.toLowerCase();break;case"appstudio":r="studio",a="playersList";break;case"Settings":switch(r="account",a){case"Account_Settings":a="overview";break;case"Integration Settings":a="integration";break;case"Access Control":a="accessControl";break;case"Transcoding Settings":a="transcoding";break;case"Account Upgrade":a="upgrade"}break;case"reports":r="analytics","Bandwidth Usage Reports"==a&&(a="usageTabTitle")}}return{moduleName:r,subtab:a,extra:n}}},kmc.preview_embed={doPreviewEmbed:function(e,t,r,a,n,i,o,s,l){var c={previewOnly:a};i&&(c.uiConfId=parseInt(i)),n?"multitab_playlist"==e?(c.playerOnly=!0,c.name=unescape(t)):(c.playlistId=e,c.playlistName=unescape(t)):(c.entryId=e,c.entryMeta={name:unescape(t),description:unescape(r),duration:s,thumbnailUrl:l},o&&(c.liveBitrates=o)),kmc.Preview.openPreviewEmbed(c,kmc.Preview.Service)},doFlavorPreview:function(e,t,r){var a=kmc.vars.default_kdp,n=kmc.Preview.getGenerator().getCode({protocol:location.protocol.substring(0,location.protocol.length-1),embedType:"legacy",entryId:e,uiConfId:parseInt(a.id),width:a.width,height:a.height,includeSeoMetadata:!1,includeHtml5Library:!1,flashVars:{ks:kmc.vars.ks,flavorId:r.asset_id}}),i='
    '+n+"
    "+"
    Entry Name:
     "+unescape(t)+"
    "+"
    Entry Id:
     "+e+"
    "+"
    Flavor Name:
     "+r.flavor_name+"
    "+"
    Flavor Asset Id:
     "+r.asset_id+"
    "+"
    Bitrate:
     "+r.bitrate+"
    "+"
    Codec:
     "+r.codec+"
    "+"
    Dimensions:
     "+r.dimensions.width+" x "+r.dimensions.height+"
    "+"
    Format:
     "+r.format+"
    "+"
    Size (KB):
     "+r.sizeKB+"
    "+"
    Status:
     "+r.status+"
    "+"
    ";kmc.layout.modal.open({width:parseInt(a.width)+120,height:parseInt(a.height)+300,title:"Flavor Preview",content:'
    '+i+"
    "})},updateList:function(e){var t=e?"playlist":"player";$.ajax({url:kmc.vars.base_url+kmc.vars.getuiconfs_url,type:"POST",data:{type:t,partner_id:kmc.vars.partner_id,ks:kmc.vars.ks},dataType:"json",success:function(t){t&&t.length&&(t.sort(function(e,t){return e.updatedAt>t.updatedAt?-1:e.updatedAti;i++){var o=r[i].split("|");t[o[0]]=o[1]}return t},s=function(e){e=o(e);var t="";for(var r in e){var a=e[r];t+=a+r}return md5(t)},l=s(r);n+="&kalsig="+l,$.ajax({type:"GET",url:n,dataType:"jsonp",data:r,cache:!1,success:a})},createShortURL:function(e,t){kmc.log("createShortURL");var r={"shortLink:objectType":"KalturaShortLink","shortLink:systemName":"KMC-PREVIEW","shortLink:fullUrl":e};kmc.client.makeRequest("shortlink_shortlink","add",r,function(e){var r=!1;t?(e.id&&(r=kmc.vars.service_url+"/tiny/"+e.id),t(r)):kmc.preview_embed.setShortURL(e.id)})}},kmc.layout={init:function(){$("#kmcHeader").bind("click",function(){$("#hTabs a").each(function(e,t){var r=$(t);return r.hasClass("menu")&&r.hasClass("active")?($("#kcms")[0].gotoPage({moduleName:r.attr("id"),subtab:r.attr("rel")}),void 0):!0})}),$("body").append('
    ')},overlay:{show:function(){$("#overlay").show()},hide:function(){$("#overlay").hide()}},modal:{el:"#modal",create:function(e){var t={el:kmc.layout.modal.el,title:"",content:"",help:"",width:680,height:"auto",className:"",contentHeight:"auto"};$.extend(t,e);var r=$(t.el),a=r.find(".title h2"),n=r.find(".content");return n.height(t.contentHeight),t.className="modal "+t.className,r.css({width:t.width,height:t.height}).attr("class",t.className),t.title?a.text(t.title).attr("title",t.title).parent().show():(a.parent().hide(),n.addClass("flash_only")),r.find(".help").remove(),a.parent().append(t.help),n[0].innerHTML=t.content,r.find(".close").click(function(){kmc.layout.modal.close(t.el),$.isFunction(e.closeCallback)&&e.closeCallback()}),r},show:function(e,t){t=void 0===t?!0:t,e=e||kmc.layout.modal.el;var r=$(e);kmc.utils.hideFlash(!0),kmc.layout.overlay.show(),r.fadeIn(600),$.browser.msie||r.css("display","block"),t&&this.position(e)},open:function(e){this.create(e);var t=e.el||kmc.layout.modal.el;this.show(t)},position:function(e){e=e||kmc.layout.modal.el;var t=$(e),r=($(window).height()-t.height())/2,a=($(window).width()-t.width())/(2+$(window).scrollLeft());r=40>r?40:r,t.css({top:r+"px",left:a+"px"})},close:function(e){e=e||kmc.layout.modal.el,$(e).fadeOut(300,function(){$(e).find(".content").html(""),kmc.layout.overlay.hide(),kmc.utils.hideFlash()})},isOpen:function(e){return e=e||kmc.layout.modal.el,$(e).is(":visible")}}},kmc.user={openSupport:function(e){var t=e.href;this.kmcHeight=$("#flash_wrap").height(),kmc.utils.hideFlash(!0),kmc.layout.overlay.show();var r='';kmc.layout.modal.create({width:550,title:"Support Request",content:r}),$("#support").load(function(){kmc.layout.modal.show(),kmc.vars.support_frame_height||(kmc.vars.support_frame_height=$("#support")[0].contentWindow.document.body.scrollHeight),$("#support").height(kmc.vars.support_frame_height),kmc.layout.modal.position()})},logout:function(){var e=kmc.functions.checkForOngoingProcess();if(e)return alert(e),!1;var t=kmc.mediator.readUrlHash();$.ajax({url:kmc.vars.base_url+"/index.php/kmc/logout",type:"POST",data:{ks:kmc.vars.ks},dataType:"json",complete:function(){window.location=kmc.vars.logoutUrl?kmc.vars.logoutUrl:kmc.vars.service_url+"/index.php/kmc/kmc#"+t.moduleName+"|"+t.subtab}})},changeSetting:function(e){var t,r;switch(e){case"password":t="Change Password",r=180;break;case"email":t="Change Email Address",r=160;break;case"name":t="Edit Name",r=200}var a=kmc.vars.kmc_secured||"https:"==location.protocol?"https":"http",n=a+"://"+window.location.hostname,i=n+kmc.vars.port+"/index.php/kmc/updateLoginData/type/"+e;i=i+"?parent="+encodeURIComponent(document.location.href);var o='';kmc.layout.modal.open({width:370,title:t,content:o}),XD.receiveMessage(function(e){kmc.layout.modal.close(),"reload"==e.data&&($.browser.msie&&8>$.browser.version&&(window.location.hash="account|user"),window.location.reload())},n)},changePartner:function(){var e,t,r,a=0,n=kmc.vars.allowed_partners.length,i='
    Please choose partner:
    ';for(e=0;n>e;e++)a=kmc.vars.allowed_partners[e].id,kmc.vars.partner_id==a?(t=' checked="checked"',r=' style="font-weight: bold"'):(t="",r=""),i+="  "+kmc.vars.allowed_partners[e].name+"";return i+='
    ',kmc.layout.modal.open({width:300,title:"Change Account",content:i}),$("#do_change_partner").click(function(){var e=kmc.vars.base_url+"/index.php/kmc/extlogin",t=$("").attr({type:"hidden",name:"ks",value:kmc.vars.ks}),r=$("").attr({type:"hidden",name:"partner_id",value:$("input[name=pid]:radio:checked").val()}),a=$("").attr({action:e,method:"post",style:"display: none"}).append(t,r);$("body").append(a),a[0].submit()}),!1}},$(function(){kmc.layout.init(),kmc.utils.handleMenu(),kmc.functions.loadSwf(window.lang),$(window).wresize(kmc.utils.resize),kmc.vars.isLoadedInterval=setInterval(kmc.utils.isModuleLoaded,200),kmc.preview_embed.updateList(),kmc.preview_embed.updateList(!0),kmc.utils.setClientIP()}),$(window).resize(function(){kmc.layout.modal.isOpen()&&kmc.layout.modal.position()}),window.onbeforeunload=kmc.functions.checkForOngoingProcess,function(e){e.fn.wresize=function(t){function r(){if(e.browser.msie)if(wresize.fired){var t=parseInt(e.browser.version,10);if(wresize.fired=!1,7>t)return!1;if(7==t){var r=e(window).width();if(r!=wresize.width)return wresize.width=r,!1}}else wresize.fired=!0;return!0}function a(e){return r()?t.apply(this,[e]):void 0}return version="1.1",wresize={fired:!1,width:0},this.each(function(){this==window?e(this).resize(a):e(this).resize(t)}),this}}(jQuery);var XD=function(){var e,t,r,a=1,n=this;return{postMessage:function(e,t,r){t&&(r=r||parent,n.postMessage?r.postMessage(e,t.replace(/([^:]+:\/\/[^\/]+).*/,"$1")):t&&(r.location=t.replace(/#.*$/,"")+"#"+ +new Date+a++ +"&"+e))},receiveMessage:function(a,i){n.postMessage?(a&&(r=function(e){return"string"==typeof i&&e.origin!==i||"[object Function]"===Object.prototype.toString.call(i)&&i(e.origin)===!1?!1:(a(e),void 0)}),n.addEventListener?n[a?"addEventListener":"removeEventListener"]("message",r,!1):n[a?"attachEvent":"detachEvent"]("onmessage",r)):(e&&clearInterval(e),e=null,a&&(e=setInterval(function(){var e=document.location.hash,r=/^#?\d+&/;e!==t&&r.test(e)&&(t=e,a({data:e.replace(r,"")}))},100)))}}}(); \ No newline at end of file diff --git a/api_v3/lib/KalturaDispatcher.php b/api_v3/lib/KalturaDispatcher.php index 563cfd43780..a217e50cbbe 100644 --- a/api_v3/lib/KalturaDispatcher.php +++ b/api_v3/lib/KalturaDispatcher.php @@ -284,6 +284,16 @@ protected function getRateLimitRule($params) { if ($key[0] == '_') { + if ($key == '_partnerId') + { + $partnerId = kCurrentContext::$ks_partner_id ? kCurrentContext::$ks_partner_id : kCurrentContext::$partner_id; + if ($partnerId != $value) + { + $matches = false; + break; + } + } + continue; } @@ -317,21 +327,28 @@ protected function rateLimit($service, $action, $params) return true; } - $keyOptions = explode(',', $rule['_key']); - $key = null; - foreach ($keyOptions as $keyOption) + if (isset($rule['_key'])) { - $value = $this->getApiParamValueWildcard($params, $keyOption); - if ($value) + $keyOptions = explode(',', $rule['_key']); + $key = null; + foreach ($keyOptions as $keyOption) { - $key = $value; - break; + $value = $this->getApiParamValueWildcard($params, $keyOption); + if ($value) + { + $key = $value; + break; + } + } + + if (!$key) + { + return true; } } - - if (!$key) + else { - return true; + $key = ''; } $cache = kCacheManager::getSingleLayerCache(kCacheManager::CACHE_TYPE_LOCK_KEYS); diff --git a/api_v3/lib/KalturaEntryService.php b/api_v3/lib/KalturaEntryService.php index efe99d1d56d..6f1b24dc2d2 100644 --- a/api_v3/lib/KalturaEntryService.php +++ b/api_v3/lib/KalturaEntryService.php @@ -1104,9 +1104,7 @@ protected function convert($entryId, $conversionProfileId = null, KalturaConvers } } - $srcFilePath = kFileSyncUtils::getLocalFilePathForKey($srcSyncKey); - - $job = kJobsManager::addConvertProfileJob(null, $entry, $srcFlavorAsset->getId(), $srcFilePath); + $job = kJobsManager::addConvertProfileJob(null, $entry, $srcFlavorAsset->getId(), $fileSync); if(!$job) return null; @@ -1550,7 +1548,10 @@ protected function updateEntry($entryId, KalturaBaseEntry $entry, $entryType = n } if ($updatedOccurred) + { myNotificationMgr::createNotification(kNotificationJobData::NOTIFICATION_TYPE_ENTRY_UPDATE, $dbEntry); + myPartnerUtils::increaseEntriesChangedNum($dbEntry); + } return $entry; } diff --git a/api_v3/lib/KalturaLiveEntryService.php b/api_v3/lib/KalturaLiveEntryService.php index 5638fb906e7..5f32a86e88c 100644 --- a/api_v3/lib/KalturaLiveEntryService.php +++ b/api_v3/lib/KalturaLiveEntryService.php @@ -486,7 +486,7 @@ private function handleRecording(LiveEntry $dbLiveEntry, entry $recordedEntry, K $keepOriginalFile = $kResource->getKeepOriginalFile(); $lockKey = "create_replacing_entry_" . $recordedEntry->getId(); - $replacingEntry = kLock::runLocked($lockKey, array('kFlowHelper', 'getReplacingEntry'), array($recordedEntry, $dbAsset, 0)); + $replacingEntry = kLock::runLocked($lockKey, array('kFlowHelper', 'getReplacingEntry'), array($recordedEntry, $dbAsset, 0, $flavorParamsId)); $this->ingestAsset($replacingEntry, $dbAsset, $filename, $keepOriginalFile, $flavorParamsId); } diff --git a/api_v3/lib/types/batch/KalturaStorageJobData.php b/api_v3/lib/types/batch/KalturaStorageJobData.php index 4249601470f..4797c27872c 100644 --- a/api_v3/lib/types/batch/KalturaStorageJobData.php +++ b/api_v3/lib/types/batch/KalturaStorageJobData.php @@ -45,6 +45,11 @@ class KalturaStorageJobData extends KalturaJobData */ public $srcFileSyncLocalPath; + /** + * @var string + */ + public $srcFileEncryptionKey; + /** * @var string @@ -64,6 +69,7 @@ class KalturaStorageJobData extends KalturaJobData "serverPassword" , "ftpPassiveMode" , "srcFileSyncLocalPath" , + "srcFileEncryptionKey" , "srcFileSyncId" , "destFileSyncStoredPath", "serverPrivateKey", diff --git a/api_v3/lib/types/entry/KalturaPlaylist.php b/api_v3/lib/types/entry/KalturaPlaylist.php index 685729baa5e..f8f84572f04 100644 --- a/api_v3/lib/types/entry/KalturaPlaylist.php +++ b/api_v3/lib/types/entry/KalturaPlaylist.php @@ -137,7 +137,7 @@ public function filtersToPlaylistContentXml() foreach($this->filters as $filter) { $filterXml = $filtersXml->addChild("filter"); - $entryFilter = new entryFilter(); + $entryFilter = new mediaEntryFilterForPlaylist(); $filter->toObject($entryFilter); $fields = $entryFilter->fields; foreach($fields as $field => $value) @@ -160,7 +160,7 @@ public function playlistContentXmlToFilters() $this->filters = new KalturaMediaEntryFilterForPlaylistArray(); foreach($listOfFilters as $entryFilterXml) { - $entryFilter = new entryFilter(); + $entryFilter = new mediaEntryFilterForPlaylist(); $entryFilter->fillObjectFromXml($entryFilterXml, "_"); $filter = new KalturaMediaEntryFilterForPlaylist(); $filter->fromObject($entryFilter); diff --git a/api_v3/lib/types/filters/KalturaMediaEntryFilterForPlaylist.php b/api_v3/lib/types/filters/KalturaMediaEntryFilterForPlaylist.php index ca2939cbd0b..9ef4411384e 100644 --- a/api_v3/lib/types/filters/KalturaMediaEntryFilterForPlaylist.php +++ b/api_v3/lib/types/filters/KalturaMediaEntryFilterForPlaylist.php @@ -8,6 +8,7 @@ class KalturaMediaEntryFilterForPlaylist extends KalturaMediaEntryFilter static private $map_between_objects = array ( "limit" => "_limit", + "name" => "_name", ); static private $order_by_map = array @@ -30,4 +31,11 @@ public function getOrderByMap() * @var int */ public $limit; + + /** + * + * + * @var string + */ + public $name; } diff --git a/api_v3/lib/types/liveReports/WSLiveReportsClient.class.php b/api_v3/lib/types/liveReports/WSLiveReportsClient.class.php index e4ad4f4e250..381db592188 100644 --- a/api_v3/lib/types/liveReports/WSLiveReportsClient.class.php +++ b/api_v3/lib/types/liveReports/WSLiveReportsClient.class.php @@ -81,6 +81,7 @@ protected function doCall($operation, array $params = array(), $type = null) $soapAction = ''; $headers = array(); $headers["KALTURA_SESSION_ID"] = (string)(new UniqueId()); + $this->setDebugLevel(0); $result = $this->call($operation, $params, $namespace, $soapAction, $headers); $this->throwError($result); diff --git a/api_v3/services/JobsService.php b/api_v3/services/JobsService.php index 7dea50ef53b..9a73893e10f 100644 --- a/api_v3/services/JobsService.php +++ b/api_v3/services/JobsService.php @@ -335,10 +335,9 @@ function addConvertProfileJobAction($entryId) $syncKey = $flavorAsset->getSyncKey(flavorAsset::FILE_SYNC_FLAVOR_ASSET_SUB_TYPE_ASSET); if(!kFileSyncUtils::file_exists($syncKey, true)) throw new KalturaAPIException(APIErrors::NO_FILES_RECEIVED); - - $inputFileSyncLocalPath = kFileSyncUtils::getLocalFilePathForKey($syncKey); - - $batchJob = kJobsManager::addConvertProfileJob(null, $entry, $flavorAsset->getId(), $inputFileSyncLocalPath); + + $fileSync = $fileSync = kFileSyncUtils::getLocalFileSyncForKey($syncKey, false); + $batchJob = kJobsManager::addConvertProfileJob(null, $entry, $flavorAsset->getId(), $fileSync); if(!$batchJob) throw new KalturaAPIException(APIErrors::UNABLE_TO_CONVERT_ENTRY); diff --git a/api_v3/services/LiveReportsService.php b/api_v3/services/LiveReportsService.php index 39b9b765b1e..9c982aa11ee 100644 --- a/api_v3/services/LiveReportsService.php +++ b/api_v3/services/LiveReportsService.php @@ -88,7 +88,7 @@ protected function getReportKava($reportType, try { - $items = call_user_func(array('kKavaLiveReportsMgr', $methodName), $this->getPartnerId(), $filter); + $items = call_user_func(array('kKavaLiveReportsMgr', $methodName), $this->getPartnerId(), $filter, $pager->pageSize); } catch (kKavaNoResultsException $e) { @@ -208,6 +208,8 @@ public function getReportAction($reportType, return $this->getReportKava($reportType, $filter, $pager); } + ini_set('memory_limit', '700M'); + $client = new WSLiveReportsClient(); $wsFilter = $filter->getWSObject(); $wsFilter->partnerId = kCurrentContext::getCurrentPartnerId(); diff --git a/batch/batches/CaptureThumb/KAsyncCaptureThumb.class.php b/batch/batches/CaptureThumb/KAsyncCaptureThumb.class.php index 749bda25d14..6df72136a94 100644 --- a/batch/batches/CaptureThumb/KAsyncCaptureThumb.class.php +++ b/batch/batches/CaptureThumb/KAsyncCaptureThumb.class.php @@ -76,12 +76,15 @@ private function captureThumb(KalturaBatchJob $job, KalturaCaptureThumbJobData $ if($data->srcAssetType == KalturaAssetType::FLAVOR) { $capturePath = $this->createUniqFileName($rootPath); - list($mediaInfoWidth, $mediaInfoHeight, $mediaInfoDar, $mediaInfoVidDur) = $this->getMediaInfoData($job->partnerId, $data->srcAssetId); + list($mediaInfoWidth, $mediaInfoHeight, $mediaInfoDar, $mediaInfoVidDur, $mediaInfoScanType) = $this->getMediaInfoData($job->partnerId, $data->srcAssetId); // generates the thumbnail $thumbMaker = new KFFMpegThumbnailMaker($mediaFile, $capturePath, self::$taskConfig->params->FFMpegCmd); $videoOffset = max(0 ,min($thumbParamsOutput->videoOffset, $mediaInfoVidDur-1)); - $created = $thumbMaker->createThumnail($videoOffset, $mediaInfoWidth, $mediaInfoHeight, null ,null, $mediaInfoDar, $mediaInfoVidDur); + $params['dar'] = $mediaInfoDar; + $params['vidDur'] = $mediaInfoVidDur; + $params['scanType'] = $mediaInfoScanType; + $created = $thumbMaker->createThumnail($videoOffset, $mediaInfoWidth, $mediaInfoHeight, $params); if(!$created || !file_exists($capturePath)) return $this->closeJob($job, KalturaBatchJobErrorTypes::APP, KalturaBatchJobAppErrors::THUMBNAIL_NOT_CREATED, "Thumbnail not created", KalturaBatchJobStatus::FAILED); @@ -181,6 +184,7 @@ private function getMediaInfoData($partnerId, $srcAssetId) $mediaInfoHeight = null; $mediaInfoDar = null; $mediaInfoVidDur = null; + $mediaInfoScanType = null; $mediaInfoFilter = new KalturaMediaInfoFilter(); $mediaInfoFilter->flavorAssetIdEqual = $srcAssetId; $this->impersonate($partnerId); @@ -193,6 +197,7 @@ private function getMediaInfoData($partnerId, $srcAssetId) $mediaInfoWidth = $mediaInfo->videoWidth; $mediaInfoHeight = $mediaInfo->videoHeight; $mediaInfoDar = $mediaInfo->videoDar; + $mediaInfoScanType = $mediaInfo->scanType; if($mediaInfo->videoDuration) $mediaInfoVidDur = $mediaInfo->videoDuration/1000; @@ -201,7 +206,7 @@ private function getMediaInfoData($partnerId, $srcAssetId) else if($mediaInfo->audioDuration) $mediaInfoVidDur = $mediaInfo->audioDuration/1000; } - return array($mediaInfoWidth, $mediaInfoHeight, $mediaInfoDar, $mediaInfoVidDur); + return array($mediaInfoWidth, $mediaInfoHeight, $mediaInfoDar, $mediaInfoVidDur, $mediaInfoScanType); } private function createUniqFileName($rootPath) diff --git a/batch/batches/Convert/KAsyncConvert.class.php b/batch/batches/Convert/KAsyncConvert.class.php index 409a29eaf45..e91832410db 100644 --- a/batch/batches/Convert/KAsyncConvert.class.php +++ b/batch/batches/Convert/KAsyncConvert.class.php @@ -193,25 +193,12 @@ protected function convertJob(KalturaBatchJob $job, KalturaConvertJobData $data) $operator = $this->getOperator($data); try { - $actualFileSyncLocalPath = null; - $key = null; - $srcFileSyncDescriptor = reset($data->srcFileSyncs); - if($srcFileSyncDescriptor) - { - $actualFileSyncLocalPath = $srcFileSyncDescriptor->actualFileSyncLocalPath; - if (is_file($actualFileSyncLocalPath)) - $key = $srcFileSyncDescriptor->fileEncryptionKey; - } + list($actualFileSyncLocalPath, $key) = self::getFirstFilePathAndKey($data->srcFileSyncs); + //TODO: in future remove the inFilePath parameter from operate method, the input files passed to operation //engine as part of the data - if (!$key) - $isDone = $this->operationEngine->operate($operator, $actualFileSyncLocalPath); - else - { - $tempClearPath = self::createTempClearFile($actualFileSyncLocalPath, $key); - $isDone = $this->operationEngine->operate($operator, $tempClearPath); - unlink($tempClearPath); - } + $isDone = $this->operate($operator, $actualFileSyncLocalPath, null, $key); + $data = $this->operationEngine->getData(); //get the data from operation engine for the cases it was changed $this->stopMonitor(); @@ -377,4 +364,31 @@ private function moveExtraFiles(KalturaConvertJobData &$data, $sharedFile) } } } + + protected static function getFirstFilePathAndKey($srcFileSyncs) + { + $actualFileSyncLocalPath = null; + $key = null; + $srcFileSyncDescriptor = reset($srcFileSyncs); + if($srcFileSyncDescriptor) + { + $actualFileSyncLocalPath = $srcFileSyncDescriptor->actualFileSyncLocalPath; + if (is_file($actualFileSyncLocalPath)) + $key = $srcFileSyncDescriptor->fileEncryptionKey; + } + return array($actualFileSyncLocalPath, $key); + } + + protected function operate($operator = null, $filePath, $configFilePath = null, $key = null) + { + if (!$key) + $res = $this->operationEngine->operate($operator, $filePath, $configFilePath); + else + { + $tempClearPath = self::createTempClearFile($filePath, $key); + $res = $this->operationEngine->operate($operator, $tempClearPath, $configFilePath); + unlink($tempClearPath); + } + return $res; + } } diff --git a/batch/batches/Convert/KAsyncConvertCollection.class.php b/batch/batches/Convert/KAsyncConvertCollection.class.php index 6863e6da152..9b1a0299c88 100644 --- a/batch/batches/Convert/KAsyncConvertCollection.class.php +++ b/batch/batches/Convert/KAsyncConvertCollection.class.php @@ -117,13 +117,11 @@ private function convertCollection(KalturaBatchJob $job, KalturaConvertCollectio $log = null; try { - $actualFileSyncLocalPath = null; - $srcFileSyncDescriptor = reset($data->srcFileSyncs); - if($srcFileSyncDescriptor) - $actualFileSyncLocalPath = $srcFileSyncDescriptor->actualFileSyncLocalPath; + list($actualFileSyncLocalPath, $key) = self::getFirstFilePathAndKey($data->srcFileSyncs); + //TODO: in future remove the inFilePath parameter from operate method, the input files passed to operation //engine as part of the data - $this->operationEngine->operate($operator, $actualFileSyncLocalPath, $data->destFileSyncLocalPath); + $this->operate($operator, $actualFileSyncLocalPath, $data->destFileSyncLocalPath, $key); } catch(KOperationEngineException $e) { diff --git a/batch/batches/Import/KAsyncImport.class.php b/batch/batches/Import/KAsyncImport.class.php index 21326138c42..76c12218fe6 100644 --- a/batch/batches/Import/KAsyncImport.class.php +++ b/batch/batches/Import/KAsyncImport.class.php @@ -18,6 +18,21 @@ */ class KAsyncImport extends KJobHandlerWorker { + + static $startTime; + static $downloadedSoFar; + const IMPORT_TIMEOUT=120; + const HEADERS_TIMEOUT=30; + public static function progressWatchDog($resource,$download_size, $downloaded, $upload_size, $uploaded) + { + if(self::$downloadedSoFar < $downloaded) + { + $time = time() - self::$startTime + self::IMPORT_TIMEOUT; + curl_setopt($resource, CURLOPT_TIMEOUT, $time); + self::$downloadedSoFar = $downloaded; + } + } + /* (non-PHPdoc) * @see KBatchBase::getType() */ @@ -42,6 +57,26 @@ protected function getMaxJobsEachRun() return 1; } + /* Will download $sourceUrl to $localPath and will monitor progress with watchDog*/ + private function curlExec($sourceUrl,$localPath) + { + self::$startTime = time(); + self::$downloadedSoFar = 0; + $progressCallBack = null; + $curlWrapper = new KCurlWrapper(self::$taskConfig->params); + $protocol = $curlWrapper->getSourceUrlProtocol($sourceUrl); + if($protocol == KCurlWrapper::HTTP_PROTOCOL_HTTP) + { + $curlWrapper->setTimeout(self::IMPORT_TIMEOUT); + $progressCallBack = array('KAsyncImport', 'progressWatchDog'); + } + $res = $curlWrapper->exec($sourceUrl, $localPath,$progressCallBack); + $responseStatusCode = $curlWrapper->getInfo(CURLINFO_HTTP_CODE); + $curlWrapper->close(); + KalturaLog::debug("Curl results: [$res] responseStatusCode [$responseStatusCode]"); + return array($res,$responseStatusCode); + } + /* * Will take a single KalturaBatchJob and fetch the URL to the job's destFile */ @@ -72,7 +107,9 @@ private function fetchFile(KalturaBatchJob $job, KalturaImportJobData $data) { $curlWrapper = new KCurlWrapper(self::$taskConfig->params); $useNoBody = ($job->executionAttempts > 1); // if the process crashed first time, tries with no body instead of range 0-0 + $curlWrapper->setTimeout(self::HEADERS_TIMEOUT); $curlHeaderResponse = $curlWrapper->getHeader($sourceUrl, $useNoBody); + $curlWrapper->close(); if(!$curlHeaderResponse || !count($curlHeaderResponse->headers)) { $this->closeJob($job, KalturaBatchJobErrorTypes::CURL, $curlWrapper->getErrorNumber(), "Couldn't read file. Error: " . $curlWrapper->getError(), KalturaBatchJobStatus::FAILED); @@ -83,22 +120,16 @@ private function fetchFile(KalturaBatchJob $job, KalturaImportJobData $data) { KalturaLog::err("Headers error: " . $curlWrapper->getError()); KalturaLog::err("Headers error number: " . $curlWrapper->getErrorNumber()); - $curlWrapper->close(); - - $curlWrapper = new KCurlWrapper(self::$taskConfig->params); } - if(!$curlHeaderResponse->isGoodCode()) { $this->closeJob($job, KalturaBatchJobErrorTypes::HTTP, $curlHeaderResponse->code, "Failed while reading file. HTTP Error: " . $curlHeaderResponse->code . " " . $curlHeaderResponse->codeName, KalturaBatchJobStatus::FAILED); - $curlWrapper->close(); return $job; } - if(isset($curlHeaderResponse->headers['content-type'])) - $contentType = $curlHeaderResponse->headers['content-type']; - if(isset($curlHeaderResponse->headers['content-length'])) - $fileSize = $curlHeaderResponse->headers['content-length']; - $curlWrapper->close(); + if(isset($curlHeaderResponse->headers['content-type'])) + $contentType = $curlHeaderResponse->headers['content-type']; + if(isset($curlHeaderResponse->headers['content-length'])) + $fileSize = $curlHeaderResponse->headers['content-length']; if( $fileSize ) { @@ -119,6 +150,7 @@ private function fetchFile(KalturaBatchJob $job, KalturaImportJobData $data) if(is_null($fileSize)) { // Read file size + $curlWrapper->setTimeout(self::HEADERS_TIMEOUT); $curlHeaderResponse = $curlWrapper->getHeader($sourceUrl, true); if(isset($curlHeaderResponse->headers['content-type'])) $contentType = $curlHeaderResponse->headers['content-type']; @@ -130,7 +162,6 @@ private function fetchFile(KalturaBatchJob $job, KalturaImportJobData $data) //When fetching headers we set curl options that than are not reset once header is fetched. //Not all servers support all the options so we need to remove them from our headers. $curlWrapper->close(); - $curlWrapper = new KCurlWrapper(self::$taskConfig->params); } if($resumeOffset) @@ -147,17 +178,12 @@ private function fetchFile(KalturaBatchJob $job, KalturaImportJobData $data) $this->updateJob($job, "Downloading file, size: $fileSize", KalturaBatchJobStatus::PROCESSING, $data); } - $res = $curlWrapper->exec($sourceUrl, $data->destFileLocalPath); - $responseStatusCode = $curlWrapper->getInfo(CURLINFO_HTTP_CODE); - KalturaLog::debug("Curl results: [$res] responseStatusCode [$responseStatusCode]"); - + list($res,$responseStatusCode) = $this->curlExec($sourceUrl, $data->destFileLocalPath); if($responseStatusCode && KCurlHeaderResponse::isError($responseStatusCode)) { if(!$resumeOffset && file_exists($data->destFileLocalPath)) unlink($data->destFileLocalPath); - $this->closeJob($job, KalturaBatchJobErrorTypes::HTTP, KalturaBatchJobAppErrors::REMOTE_DOWNLOAD_FAILED, "Failed while reading file. HTTP Error: [$responseStatusCode]", KalturaBatchJobStatus::RETRY); - $curlWrapper->close(); return $job; } @@ -167,7 +193,6 @@ private function fetchFile(KalturaBatchJob $job, KalturaImportJobData $data) if($errNumber != CURLE_OPERATION_TIMEOUTED) { $this->closeJob($job, KalturaBatchJobErrorTypes::CURL, $errNumber, "Error: " . $curlWrapper->getError(), KalturaBatchJobStatus::RETRY); - $curlWrapper->close(); return $job; } else @@ -177,19 +202,15 @@ private function fetchFile(KalturaBatchJob $job, KalturaImportJobData $data) if($actualFileSize == $resumeOffset) { $this->closeJob($job, KalturaBatchJobErrorTypes::CURL, $errNumber, "No new information. Error: " . $curlWrapper->getError(), KalturaBatchJobStatus::RETRY); - $curlWrapper->close(); return $job; } if(!$fileSize) { $this->closeJob($job, KalturaBatchJobErrorTypes::CURL, $errNumber, "Received timeout, but no filesize available. Completed size [$actualFileSize]" . $curlWrapper->getError(), KalturaBatchJobStatus::RETRY); - $curlWrapper->close(); return $job; } } } - $curlWrapper->close(); - if(!file_exists($data->destFileLocalPath)) { $this->closeJob($job, KalturaBatchJobErrorTypes::APP, KalturaBatchJobAppErrors::OUTPUT_FILE_DOESNT_EXIST, "Error: output file doesn't exist", KalturaBatchJobStatus::RETRY); diff --git a/batch/batches/KBatchBase.class.php b/batch/batches/KBatchBase.class.php index 6d3a1392c15..ea3f95614e9 100644 --- a/batch/batches/KBatchBase.class.php +++ b/batch/batches/KBatchBase.class.php @@ -644,11 +644,16 @@ function log($message) */ public static function createTempClearFile($path, $key) { - $iv = kConf::get("encryption_iv"); + $iv = self::getIV(); $tempPath = sys_get_temp_dir(). "/clear_." . pathinfo($path, PATHINFO_BASENAME); KalturaLog::info("Creating tempFile with Key is: [$key] iv: [$iv] for path [$path] at [$tempPath]"); $plainData = kEncryptFileUtils::getEncryptedFileContent($path, $key, $iv); kFileBase::setFileContent($tempPath, $plainData); return $tempPath; } + + public static function getIV() + { + return kConf::get("encryption_iv"); + } } diff --git a/batch/batches/LiveReportExport/Engines/LiveReportLocationEngine.php b/batch/batches/LiveReportExport/Engines/LiveReportLocationEngine.php index b6b02458123..62d15100e4d 100644 --- a/batch/batches/LiveReportExport/Engines/LiveReportLocationEngine.php +++ b/batch/batches/LiveReportExport/Engines/LiveReportLocationEngine.php @@ -5,8 +5,8 @@ */ class LiveReportLocation1MinEngine extends LiveReportEngine { - const TIME_CHUNK = 600; - const MAX_RECORDS_PER_REQUEST = 1000; + const TIME_CHUNK = 300; + const MAX_RECORDS_PER_CHUNK = 10000; const AGGREGATION_CHUNK = LiveReportConstants::SECONDS_60; protected $dateFormatter; @@ -28,44 +28,32 @@ public function run($fp, array $args = array()) { $objs = array(); $lastTimeGroup = null; - $fix = 0; // The report is inclussive, therefore starting from the the second request we shouldn't query twice for($curTime = $fromTime; $curTime < $toTime; $curTime = $curTime + self::TIME_CHUNK) { - $curTo = min($toTime, $curTime + self::TIME_CHUNK); + $curTo = min($toTime, $curTime + self::TIME_CHUNK - LiveReportConstants::SECONDS_10); - $pageIndex = 0; - $moreResults = true; + $results = $this->getRecords($curTime, $curTo, $args[LiveReportConstants::ENTRY_IDS]); - while($moreResults) { - $pageIndex++; - $results = $this->getRecords($curTime + $fix, $curTo, $args[LiveReportConstants::ENTRY_IDS], $pageIndex); - $moreResults = self::MAX_RECORDS_PER_REQUEST * $pageIndex < $results->totalCount; - if($results->totalCount == 0) - continue; + foreach($results->objects as $result) { - foreach($results->objects as $result) { - - $groupTime = $this->roundTime($result->timestamp); - - if(is_null($lastTimeGroup)) - $lastTimeGroup = $groupTime; - - if($lastTimeGroup < $groupTime) { - $this->printRows($fp, $objs, $lastTimeGroup, $showDvr); - $lastTimeGroup = $groupTime; - } - - $country = $result->country->name; - $city = $result->city->name; - $key = ($result->entryId . "#" . $country . "#" . $city); - - if(!array_key_exists($key, $objs)) { - $objs[$key] = array(); - } - $objs[$key][] = $result; - + $groupTime = $this->roundTime($result->timestamp); + + if(is_null($lastTimeGroup)) + $lastTimeGroup = $groupTime; + + if($lastTimeGroup < $groupTime) { + $this->printRows($fp, $objs, $lastTimeGroup, $showDvr); + $lastTimeGroup = $groupTime; + } + + $country = $result->country->name; + $city = $result->city->name; + $key = ($result->entryId . "#" . $country . "#" . $city); + + if(!array_key_exists($key, $objs)) { + $objs[$key] = array(); } + $objs[$key][] = $result; } - $fix = LiveReportConstants::SECONDS_10; } $this->printRows($fp, $objs, $lastTimeGroup, $showDvr); @@ -73,7 +61,7 @@ public function run($fp, array $args = array()) { // ASUMPTION - we have a single entry ID (that's a constraint of the cassandra) // and the results are ordered from the oldest to the newest - protected function getRecords($fromTime, $toTime, $entryId, $pageIdx) { + protected function getRecords($fromTime, $toTime, $entryId) { $reportType = KalturaLiveReportType::ENTRY_GEO_TIME_LINE; $filter = new KalturaLiveReportInputFilter(); @@ -82,8 +70,8 @@ protected function getRecords($fromTime, $toTime, $entryId, $pageIdx) { $filter->entryIds = $entryId; $pager = new KalturaFilterPager(); - $pager->pageIndex = $pageIdx; - $pager->pageSize = self::MAX_RECORDS_PER_REQUEST; + $pager->pageIndex = 1; + $pager->pageSize = self::MAX_RECORDS_PER_CHUNK; return KBatchBase::$kClient->liveReports->getReport($reportType, $filter, $pager); } diff --git a/batch/batches/PostConvert/KAsyncPostConvert.class.php b/batch/batches/PostConvert/KAsyncPostConvert.class.php index cf5a17db316..4143393ecec 100644 --- a/batch/batches/PostConvert/KAsyncPostConvert.class.php +++ b/batch/batches/PostConvert/KAsyncPostConvert.class.php @@ -57,8 +57,13 @@ private function postConvert(KalturaBatchJob $job, KalturaPostConvertJobData $da { $srcFileSyncDescriptor = reset($data->srcFileSyncs); $mediaFile = null; - if($srcFileSyncDescriptor) + $key = null; + if($srcFileSyncDescriptor) + { $mediaFile = trim($srcFileSyncDescriptor->fileSyncLocalPath); + $key = $srcFileSyncDescriptor->fileEncryptionKey; + } + if(!$data->flavorParamsOutput || !$data->flavorParamsOutput->sourceRemoteStorageProfileId) { @@ -83,7 +88,15 @@ private function postConvert(KalturaBatchJob $job, KalturaPostConvertJobData $da if($engine) { KalturaLog::info("Media info engine [" . get_class($engine) . "]"); - $mediaInfo = $engine->getMediaInfo(); + if (!$key) + $mediaInfo = $engine->getMediaInfo(); + else + { + $tempClearPath = self::createTempClearFile($mediaFile, $key); + $engine->setFilePath($tempClearPath); + $mediaInfo = $engine->getMediaInfo(); + unlink($tempClearPath); + } } else { @@ -150,7 +163,9 @@ private function postConvert(KalturaBatchJob $job, KalturaPostConvertJobData $da // generates the thumbnail $thumbMaker = new KFFMpegThumbnailMaker($mediaFile, $thumbPath, KBatchBase::$taskConfig->params->FFMpegCmd); - $created = $thumbMaker->createThumnail($data->thumbOffset, $mediaInfo->videoWidth, $mediaInfo->videoHeight, null, null, $mediaInfo->videoDar); + $params['dar'] = $mediaInfo->videoDar; + $params['scanType'] = $mediaInfo->scanType; + $created = $thumbMaker->createThumnail($data->thumbOffset, $mediaInfo->videoWidth, $mediaInfo->videoHeight, $params); if(!$created || !file_exists($thumbPath)) { diff --git a/batch/batches/Provision/Engines/KProvisionEngineUniversalAkamai.php b/batch/batches/Provision/Engines/KProvisionEngineUniversalAkamai.php index 4515710ac2b..5cf96efd09b 100644 --- a/batch/batches/Provision/Engines/KProvisionEngineUniversalAkamai.php +++ b/batch/batches/Provision/Engines/KProvisionEngineUniversalAkamai.php @@ -71,7 +71,7 @@ public function provide(KalturaBatchJob $job, KalturaProvisionJobData $data) $res = $this->provisionStream($data); if (!$res) { - return new KProvisionEngineResult(KalturaBatchJobStatus::FAILED, "Error: no result received for connection"); + return new KProvisionEngineResult(KalturaBatchJobStatus::FAILED, "Error: no result received for connection"); } KalturaLog::info ("Request to provision stream returned result: $res"); @@ -82,7 +82,7 @@ public function provide(KalturaBatchJob $job, KalturaProvisionJobData $data) { //There is always only 1 error listed in the XML $error = $errors[0]; - return new KProvisionEngineResult(KalturaBatchJobStatus::FAILED, "Error: ". strval($error[0])); + return new KProvisionEngineResult(KalturaBatchJobStatus::RETRY, "Error: ". strval($error[0])); } //Otherwise, the stream provision request probably returned OK, attempt to parse it as a new stream XML try { @@ -93,7 +93,7 @@ public function provide(KalturaBatchJob $job, KalturaProvisionJobData $data) return new KProvisionEngineResult(KalturaBatchJobStatus::FAILED, "Error: ". $e->getMessage()); } - return new KProvisionEngineResult(KalturaBatchJobStatus::FINISHED, 'Succesfully provisioned entry', $data); + return new KProvisionEngineResult(KalturaBatchJobStatus::FINISHED, 'Successfully provisioned entry', $data); } @@ -226,9 +226,9 @@ public function delete(KalturaBatchJob $job, KalturaProvisionJobData $data) */ public function checkProvisionedStream(KalturaBatchJob $job, KalturaProvisionJobData $data) { - KalturaLog::info("Retrieving stream with ID [". $data->streamID ."]" ); - $url = self::$baseServiceUrl . "/{$this->domainName}/stream/".$data->streamID; + KalturaLog::info("Retrieving stream with ID [". $data->streamID ."] from URL [$url]" ); + $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER , true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION , true); @@ -241,10 +241,8 @@ public function checkProvisionedStream(KalturaBatchJob $job, KalturaProvisionJob } $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - if($httpCode<=200 && $httpCode>300) - { - return new KProvisionEngineResult(KalturaBatchJobStatus::FAILED, "Error: retrieval failed"); - } + if (KCurlHeaderResponse::isError($httpCode)) + return new KProvisionEngineResult(KalturaBatchJobStatus::RETRY, "Error: retrieval failed , retrying. HTTP Error code:".$httpCode); KalturaLog::info("Result received: $result"); $resultXML = new SimpleXMLElement($result); @@ -274,4 +272,4 @@ public function checkProvisionedStream(KalturaBatchJob $job, KalturaProvisionJob } -} \ No newline at end of file +} diff --git a/batch/batches/Storage/Engine/KExportEngine.php b/batch/batches/Storage/Engine/KExportEngine.php index 5386fd735e2..855a683621b 100644 --- a/batch/batches/Storage/Engine/KExportEngine.php +++ b/batch/batches/Storage/Engine/KExportEngine.php @@ -5,13 +5,12 @@ abstract class KExportEngine { /** - * @var KalturaStorageExportJobData + * @var KalturaStorageJobData */ protected $data; /** - * @param KalturaStorageExportJobData $data - * @param int $jobSubType + * @param KalturaStorageJobData $data */ public function __construct(KalturaStorageJobData $data) { diff --git a/batch/batches/Storage/Engine/KFileTransferExportEngine.php b/batch/batches/Storage/Engine/KFileTransferExportEngine.php index 3d55e20e716..88e0ce40215 100644 --- a/batch/batches/Storage/Engine/KFileTransferExportEngine.php +++ b/batch/batches/Storage/Engine/KFileTransferExportEngine.php @@ -6,6 +6,8 @@ class KFileTransferExportEngine extends KExportEngine protected $destFile; protected $protocol; + + protected $encryptionKey; /* (non-PHPdoc) * @see KExportEngine::init() @@ -16,6 +18,7 @@ function __construct($data, $jobSubType) { $this->protocol = $jobSubType; $this->srcFile = str_replace('//', '/', trim($this->data->srcFileSyncLocalPath)); $this->destFile = str_replace('//', '/', trim($this->data->destFileSyncStoredPath)); + $this->encryptionKey = $this->data->srcFileEncryptionKey; } /* (non-PHPdoc) @@ -65,7 +68,14 @@ function export() { if (is_file($this->srcFile)) { - $engine->putFile($this->destFile, $this->srcFile, $this->data->force); + if (!$this->encryptionKey) + $engine->putFile($this->destFile, $this->srcFile, $this->data->force); + else + { + $tempPath = KBatchBase::createTempClearFile($this->srcFile, $this->encryptionKey); + $engine->putFile($this->destFile, $tempPath, $this->data->force); + unlink($tempPath); + } if(KBatchBase::$taskConfig->params->chmod) { try { diff --git a/configurations/admin.template.ini b/configurations/admin.template.ini index bdd3cb5e781..afae3506199 100644 --- a/configurations/admin.template.ini +++ b/configurations/admin.template.ini @@ -977,7 +977,7 @@ moduls.MediaRepurposing.group = GROUP_ENABLE_DISABLE_FEATURES moduls.V3Studio.enabled = true moduls.V3Studio.permissionType = 2 -moduls.V3Studio.label = "Enable V3 Studio" +moduls.V3Studio.label = "Show V3 Studio" moduls.V3Studio.permissionName = FEATURE_V3_STUDIO_PERMISSION moduls.V3Studio.group = GROUP_ENABLE_DISABLE_FEATURES diff --git a/configurations/base.ini b/configurations/base.ini index eed313d9f20..bca83ff25c9 100644 --- a/configurations/base.ini +++ b/configurations/base.ini @@ -97,16 +97,17 @@ editors_flex_wrapper_version = v1.01 kdp_wrapper_version = v11.0 kdp3_wrapper_stats_url = kdp3_wrapper_version = v34.0 -html5_version = v2.63.3 +html5_version = v2.64 clipapp_version = v1.3 kmc_secured_login = false studio_version = v2.1.0 +studio_v3_version = v3.0.0 liveanalytics_version = v2.6 usagedashboard_version = v0.11.2 -live_dashboard_version = v0.2.1 +live_dashboard_version = v1.2.4 -kmc_version = v5.43.6 +kmc_version = v5.43.9 new_partner_kmc_version = 4 limelight_madiavault_password = @@ -531,3 +532,10 @@ allowed[] = arf poll_poll_vote = "/../../plugins/poll/lib/PollActions.php" poll_poll_getVote = "/../../plugins/poll/lib/PollActions.php" beacon_beacon_add = "/../../plugins/beacon/lib/model/kBeaconCacheLayerActions.php" + +[file_descriptions_black_list] +fileDescriptions[] = "M3U playlist, ASCII text";//hls on all platforms +fileDescriptions[] = "XML 1.0 document, ASCII text";//mpd on ubuntu16 +fileDescriptions[] = "XML document text";//mpd on ubuntu 14,12 +fileDescriptions[] = "XML document text";//mpd on Fedora 11 + diff --git a/deployment/permissions/service.cuepoint.cuepoint.ini b/deployment/permissions/service.cuepoint.cuepoint.ini index 6055a08e6a7..f49eb8db4c2 100644 --- a/deployment/permissions/service.cuepoint.cuepoint.ini +++ b/deployment/permissions/service.cuepoint.cuepoint.ini @@ -78,7 +78,7 @@ permissionItem9.param3 = permissionItem9.param4 = permissionItem9.param5 = permissionItem9.tags = -permissionItem9.permissions = -1>PARTNER_-1_GROUP_*_PERMISSION +permissionItem9.permissions = -1>PARTNER_-1_GROUP_*_PERMISSION,WEBCAST_PRODUCER_PERMISSION permissionItem10.service = cuepoint_cuepoint permissionItem10.action = clone diff --git a/deployment/updates/scripts/add_permissions/2017_12_14_allow_webcast_producer_to_change_cue_point_status.php b/deployment/updates/scripts/add_permissions/2017_12_14_allow_webcast_producer_to_change_cue_point_status.php new file mode 100644 index 00000000000..c18f68c86a0 --- /dev/null +++ b/deployment/updates/scripts/add_permissions/2017_12_14_allow_webcast_producer_to_change_cue_point_status.php @@ -0,0 +1,7 @@ + Entry view mode or recording status changes - {view_mode,recording_status} + view_mode,recording_status $scope->getObject()->getType() diff --git a/infra/cdl/kdl/KDLMediaDataSet.php b/infra/cdl/kdl/KDLMediaDataSet.php index 129303dbe25..eee7e2a5ec4 100644 --- a/infra/cdl/kdl/KDLMediaDataSet.php +++ b/infra/cdl/kdl/KDLMediaDataSet.php @@ -385,7 +385,7 @@ public function IsCondition($condition) $containerFormats = array("mp4","mxf","wmv3","mpegps","mpegts","webm","mp3"); $videoCodecs = array("h264","h265","vp6","vp8","vp9","wmv3","mpeg2"); $audioCodecs = array("mp3","aac","mpeg2","pcm","ac3","eac3"); - $allowedFormats = array_merge($containerFormats, $videoCodecs, $audioCodecs); + $allowedFormats = array_unique(array_merge($containerFormats, $videoCodecs, $audioCodecs)); $allowedFormats[] = "undefined"; $allowedChars = ' +-*/()!=<>&|;'; $tok = strtok($condition, $allowedChars); diff --git a/infra/chunkedEncode/KBaseChunkedEncodeSessionManager.php b/infra/chunkedEncode/KBaseChunkedEncodeSessionManager.php index 3de86b649cb..422be003d01 100644 --- a/infra/chunkedEncode/KBaseChunkedEncodeSessionManager.php +++ b/infra/chunkedEncode/KBaseChunkedEncodeSessionManager.php @@ -81,9 +81,10 @@ public function Generate() public function Initialize() { $chunker = $this->chunker; - $rv = $chunker->Initialize(); + $rv = $chunker->Initialize($msgStr); if($rv!==true){ $this->returnStatus = KChunkedEncodeReturnStatus::InitializeError; + $this->returnMessages[] = $msgStr; return $rv; } if(!isset($this->name)) @@ -103,10 +104,11 @@ public function Initialize() $this->videoCmdLines = $videoCmdLines; $cmdLine = $chunker->BuildAudioCommandLine(); - $logFilename = $chunker->getSessionName("audio").".log"; - $cmdLine = "time $cmdLine > $logFilename 2>&1"; - $this->audioCmdLines = array($cmdLine); - + if(isset($cmdLine)){ + $logFilename = $chunker->getSessionName("audio").".log"; + $cmdLine = "time $cmdLine > $logFilename 2>&1"; + $this->audioCmdLines = array($cmdLine); + } $this->SerializeSession(); return true; } diff --git a/infra/chunkedEncode/KChunkedEncode.php b/infra/chunkedEncode/KChunkedEncode.php index d06377556cf..f8d00c50881 100644 --- a/infra/chunkedEncode/KChunkedEncode.php +++ b/infra/chunkedEncode/KChunkedEncode.php @@ -42,7 +42,7 @@ public function __construct($setup) /******************** * Initialize the chunked encode session */ - public function Initialize() + public function Initialize(&$msgStr) { KalturaLog::log(date("Y-m-d H:i:s")); @@ -419,6 +419,7 @@ protected function adjustTimeRelatedFilters($cmdLine, $chunkIdx, $start, $chunkW /* * Handle WM fade in's/out's */ + $lastLabelOut = null; if(isset($this->params->videoFilters->fadeFilters)){ $filterGraph = clone $filterGraphBase; $filterGraph->entities = array(); @@ -435,7 +436,7 @@ protected function adjustTimeRelatedFilters($cmdLine, $chunkIdx, $start, $chunkW continue; $filterGraph->RemoveChain($filterGraph->entities[$chainIdx]); } - $adjustedFilterStr = $filterGraph->CompoundString(); + $adjustedFilterStr = $filterGraph->CompoundString($lastLabelOut); } /* @@ -452,6 +453,9 @@ protected function adjustTimeRelatedFilters($cmdLine, $chunkIdx, $start, $chunkW $adjustedSubsFilename, $cmdLineArr[$filterIdx+1]); } } + else { + $adjustedFilterStr = str_replace($lastLabelOut, "", $adjustedFilterStr); + } if(isset($adjustedFilterStr)) { KalturaLog::log($adjustedFilterStr); diff --git a/infra/chunkedEncode/KFFmpegFilterGraphHelper.php b/infra/chunkedEncode/KFFmpegFilterGraphHelper.php index 51a20cee0e8..54a8cd30d3e 100644 --- a/infra/chunkedEncode/KFFmpegFilterGraphHelper.php +++ b/infra/chunkedEncode/KFFmpegFilterGraphHelper.php @@ -226,7 +226,7 @@ public function Parse($filterGraphStr) /******************** * CompoundString */ - public function CompoundString() + public function CompoundString(&$lastLabelOut) { $str = null; $chainArr = array(); @@ -257,8 +257,11 @@ public function CompoundString() $filterStr.= "=".implode($filter->delim,$fieldArr); if(isset($filter->labelOut)){ - $filterStr.="[$filter->labelOut]"; + $lastLabelOut ="[$filter->labelOut]"; + $filterStr.= $lastLabelOut; } + else + $lastLabelOut = ""; $filterArr[] = $filterStr; } $chainStr.= implode(',',$filterArr); diff --git a/infra/content/kXsd.php b/infra/content/kXsd.php index 4542333f566..7e263ee3a00 100644 --- a/infra/content/kXsd.php +++ b/infra/content/kXsd.php @@ -461,13 +461,13 @@ public static function transformXmlFile($xmlPath, $xsdPath, $xslPath) * @param string $xslPath * @return bool:string false if failed, xml text if succeed */ - public static function transformXmlData($xml, $xsdPath, $xslPath) + public static function transformXmlData($xml, $xsdPath, $xslStr) { $from = new KDOMDocument(); $from->loadXML($xml); $xsl = new KDOMDocument(); - $xsl->load($xslPath); + $xsl->loadXML($xslStr); $proc = new XSLTProcessor; $proc->importStyleSheet($xsl); diff --git a/infra/general/KCurlWrapper.class.php b/infra/general/KCurlWrapper.class.php index 1bbc20a3b4c..cbf07c6221f 100644 --- a/infra/general/KCurlWrapper.class.php +++ b/infra/general/KCurlWrapper.class.php @@ -493,9 +493,10 @@ public function getHeader($sourceUrl, $noBody = false) /** * @param string $sourceUrl * @param string $destFile + * @param function pointer * @return boolean */ - public function exec($sourceUrl, $destFile = null) + public function exec($sourceUrl, $destFile = null,$progressCallBack = null) { $this->setSourceUrlAndprotocol($sourceUrl); @@ -509,7 +510,11 @@ public function exec($sourceUrl, $destFile = null) curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, $returnTransfer); if (!is_null($destFd)) curl_setopt($this->ch, CURLOPT_FILE, $destFd); - + if($progressCallBack) + { + curl_setopt($this->ch, CURLOPT_NOPROGRESS, false); + curl_setopt($this->ch, CURLOPT_PROGRESSFUNCTION, $progressCallBack); + } $ret = curl_exec($this->ch); if (!is_null($destFd)) { @@ -518,7 +523,34 @@ public function exec($sourceUrl, $destFile = null) return $ret; } - + + public function getSourceUrlProtocol($sourceUrl) + { + $protocol = null; + $sourceUrl = trim($sourceUrl); + try + { + $url_parts = parse_url( $sourceUrl ); + if ( isset ( $url_parts["scheme"] ) ) + { + if (in_array ($url_parts["scheme"], array ('http', 'https'))) + { + $protocol = self::HTTP_PROTOCOL_HTTP; + } + elseif ( $url_parts["scheme"] == "ftp" || $url_parts["scheme"] == "ftps" ) + { + $protocol = self::HTTP_PROTOCOL_FTP; + } + } + } + catch ( Exception $exception ) + { + throw new Exception($exception->getMessage()); + } + return $protocol; + } + + public function setSourceUrlAndprotocol($sourceUrl) { $sourceUrl = trim($sourceUrl); @@ -529,20 +561,20 @@ public function setSourceUrlAndprotocol($sourceUrl) { if ( $url_parts["scheme"] == "ftp" || $url_parts["scheme"] == "ftps" ) $this->protocol = self::HTTP_PROTOCOL_FTP; - + if ( in_array ($url_parts["scheme"], array ('http', 'https')) && isset ($url_parts['user']) ) { curl_setopt ($this->ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); } } - + } catch ( Exception $exception ) { throw new Exception($exception->getMessage()); } KalturaLog::info("Setting source URL to [$sourceUrl]"); - + $sourceUrl = self::encodeUrl($sourceUrl); curl_setopt($this->ch, CURLOPT_URL, $sourceUrl); } diff --git a/infra/media/mediaInfoParser/KBaseMediaParser.php b/infra/media/mediaInfoParser/KBaseMediaParser.php index bbdade45bf0..67931ee7cc8 100644 --- a/infra/media/mediaInfoParser/KBaseMediaParser.php +++ b/infra/media/mediaInfoParser/KBaseMediaParser.php @@ -57,6 +57,14 @@ public function getMediaInfo() return $this->parseOutput($output); } + /** + * @param string $filePath + */ + public function setFilePath($filePath) + { + $this->filePath = $filePath; + } + /** * @return string */ diff --git a/infra/media/thumbnailMaker/KBaseThumbnailMaker.php b/infra/media/thumbnailMaker/KBaseThumbnailMaker.php index 4a8cad67e65..f5939a7ea51 100644 --- a/infra/media/thumbnailMaker/KBaseThumbnailMaker.php +++ b/infra/media/thumbnailMaker/KBaseThumbnailMaker.php @@ -24,10 +24,12 @@ public function __construct($srcPath, $targetPath) $this->targetPath = $targetPath; } - public function createThumnail($position = null, $width = null, $height = null, $frameCount = 1, $targetType = "image2", $dar = null) + public function createThumnail($position = null, $width = null, $height = null, $params = array()) { - KalturaLog::debug("position[$position], width[$width], height[$height], frameCount[$frameCount], frameCount[$frameCount], dar[$dar]"); - $cmd = $this->getCommand($position, $width, $height, $frameCount, $targetType); + $params = self::normalizeParams($params); + + KalturaLog::debug("position[$position], width[$width], height[$height], params[".serialize($params)."]"); + $cmd = $this->getCommand($position, $width, $height, $params); KalturaLog::info("Executing: $cmd"); $returnValue = null; @@ -43,6 +45,31 @@ public function createThumnail($position = null, $width = null, $height = null, return true; } + protected static function normalizeParams($params = array()) + { + if(!array_key_exists('frameCount', $params)){ + $params['frameCount'] = 1; + } + + if(!array_key_exists ('targetType', $params)){ + $params['targetType'] = "image2"; + } + + if(!array_key_exists ('dar', $params)){ + $params['dar'] = null; + } + + if(!array_key_exists ('vidDur', $params)){ + $params['vidDur'] = null; + } + + if(!array_key_exists ('scanType', $params)){ + $params['scanType'] = null; + } + + return $params; + } + /** * @return string */ @@ -52,4 +79,4 @@ protected abstract function getCommand(); * @return int */ protected abstract function parseOutput($output); -} \ No newline at end of file +} diff --git a/infra/media/thumbnailMaker/KFFMpegThumbnailMaker.php b/infra/media/thumbnailMaker/KFFMpegThumbnailMaker.php index 1c7f2707c43..183cdbbb87b 100644 --- a/infra/media/thumbnailMaker/KFFMpegThumbnailMaker.php +++ b/infra/media/thumbnailMaker/KFFMpegThumbnailMaker.php @@ -16,18 +16,17 @@ public function __construct($srcPath, $targetPath, $cmdPath = 'ffmpeg') parent::__construct($srcPath, $targetPath); } - public function createThumnail($position = null, $width = null, $height = null, $frameCount = 1, $targetType = "image2", $dar = null, $vidDur = null) + public function createThumnail($position = null, $width = null, $height = null, $params = array()) { - if(!isset($frameCount)) - $frameCount = 1; - if(!isset($targetType)) - $targetType = "image2"; - KalturaLog::debug("position[$position], width[$width], height[$height], frameCount[$frameCount], frameCount[$frameCount], dar[$dar], vidDur[$vidDur]"); + $params = self::normalizeParams($params); + + KalturaLog::debug("position[$position], width[$width], height[$height], params[".serialize($params)."]"); + $dar = $params['dar']; if(isset($dar) && $dar>0 && isset($height)){ - $width = floor(round($height*$dar) /2) * 2; + $width = floor(round($height*$dar) /2) * 2; } // TODO - calculate the width and height according to dar - $cmdArr = $this->getCommand($position, $width, $height, $frameCount, $targetType, $vidDur); + $cmdArr = $this->getCommand($position, $width, $height, $params); $cmd= $cmdArr[0]; $rv = null; @@ -66,8 +65,16 @@ public function createThumnail($position = null, $width = null, $height = null, return $rv? false: true; } - protected function getCommand($position = null, $width = null, $height = null, $frameCount = 1, $targetType = "image2", $vidDur = null) + protected function getCommand($position = null, $width = null, $height = null, $params = array()) { + $frameCount = $params['frameCount']; + $targetType = $params['targetType']; + $vidDur = $params['vidDur']; + $scanType = $params['scanType']; + if(isset($scanType) && $scanType==1) + $scanType = " -deinterlace"; + else $scanType = null; + $dimensions = (is_null($width) || is_null($height)) ? '' : ("-s ". $width ."x" . $height); //In case the video length is less than 30 sec to the seek in the decoding phase and not in the muxing phase (related to SUP-2172) @@ -84,9 +91,9 @@ protected function getCommand($position = null, $width = null, $height = null, $ $cmdArr = array(); // '-noautorotate' to adjust to ffm2.7.2 that automatically normalizes rotated sources - $cmdArr[] = "$this->cmdPath $position_str -noautorotate -i $this->srcPath -an -y -r 1 $dimensions -vframes $frameCount -f $targetType $position_str_suffix" . + $cmdArr[] = "$this->cmdPath $position_str -noautorotate -i $this->srcPath -an$scanType -y -r 1 $dimensions -vframes $frameCount -f $targetType $position_str_suffix" . " $this->targetPath >> $this->targetPath.log 2>&1"; - $cmdArr[] = "$this->cmdPath -noautorotate -i $this->srcPath $position_str -an -y -r 1 $dimensions -vframes $frameCount -f $targetType" . + $cmdArr[] = "$this->cmdPath -noautorotate -i $this->srcPath $position_str -an$scanType -y -r 1 $dimensions -vframes $frameCount -f $targetType" . " $this->targetPath >> $this->targetPath.log 2>&1"; return $cmdArr; diff --git a/infra/storage/kFile.class.php b/infra/storage/kFile.class.php index 1cbf36bb725..77dba2f21c0 100644 --- a/infra/storage/kFile.class.php +++ b/infra/storage/kFile.class.php @@ -504,22 +504,14 @@ public static function findFileTypeByFileCmd($filePath) $fileBrief = shell_exec('file -b ' . $realPath); if(kString::beginsWith($fileBrief,self::MO_PATTERN)) $fileType = 'application/mo'; - else if(strpos($fileBrief,self::TEXT)!==false) - $fileType = self::TEXT; } return $fileType; } - public static function isFileTypeText($filePath) + public static function getFileDescription($realPath) { - $isText=false; - $fileType=self::findFileTypeByFileCmd($filePath); - if($fileType==self::TEXT) - $isText=true; - - return $isText; + return shell_exec('file -b '.$realPath); } - } diff --git a/plugins/content/document/lib/events/DocumentCreatedHandler.php b/plugins/content/document/lib/events/DocumentCreatedHandler.php index 4f9b90a7ed6..9c2b53d563c 100644 --- a/plugins/content/document/lib/events/DocumentCreatedHandler.php +++ b/plugins/content/document/lib/events/DocumentCreatedHandler.php @@ -119,9 +119,8 @@ public function objectAdded(BaseObject $object, BatchJob $raisedJob = null) if($entry->getConversionQuality() > 0) { $syncKey = $object->getSyncKey(flavorAsset::FILE_SYNC_FLAVOR_ASSET_SUB_TYPE_ASSET); - $path = kFileSyncUtils::getLocalFilePathForKey($syncKey); - - kJobsManager::addConvertProfileJob($raisedJob, $entry, $object->getId(), $path); + $fileSync = kFileSyncUtils::getLocalFileSyncForKey($syncKey, false); + kJobsManager::addConvertProfileJob($raisedJob, $entry, $object->getId(), $fileSync); } else { diff --git a/plugins/drm/admin/DrmAdminApiAction.php b/plugins/drm/admin/DrmAdminApiAction.php index 18eadfda2fc..50b24953305 100644 --- a/plugins/drm/admin/DrmAdminApiAction.php +++ b/plugins/drm/admin/DrmAdminApiAction.php @@ -62,7 +62,7 @@ public function doAction(Zend_Controller_Action $action) private function translateName($name) { - $nameArray = array('provider_sign_key' => 'providerSignKey'); + $nameArray = array('provider_sign_key' => 'providerSignKey', 'key_pem' => 'keyPem'); if (isset($nameArray[$name])) return $nameArray[$name]; return $name; diff --git a/plugins/drm/admin/forms/AdminApiConfigure.php b/plugins/drm/admin/forms/AdminApiConfigure.php index 8c4f55adcbe..3c2cf0bddba 100644 --- a/plugins/drm/admin/forms/AdminApiConfigure.php +++ b/plugins/drm/admin/forms/AdminApiConfigure.php @@ -38,7 +38,7 @@ public function init() private function addDocFields() { $partnerDocFields = array('provider_sign_key', 'key', 'iv', 'provider', 'seed', 'cas_username', 'cas_password'); - $fpsDocFields = array('ask', 'keyPem'); + $fpsDocFields = array('ask', 'key_pem'); foreach($partnerDocFields as $field) $this->addTextElement($field, "$field:", "", $this->readOnly); diff --git a/plugins/event_notification/providers/email/lib/batch/recipients/KEmailNotificationCategoryRecipientEngine.php b/plugins/event_notification/providers/email/lib/batch/recipients/KEmailNotificationCategoryRecipientEngine.php index 9b43e64c3a9..0afd4aacf88 100644 --- a/plugins/event_notification/providers/email/lib/batch/recipients/KEmailNotificationCategoryRecipientEngine.php +++ b/plugins/event_notification/providers/email/lib/batch/recipients/KEmailNotificationCategoryRecipientEngine.php @@ -15,24 +15,35 @@ function getRecipients(array $contentParameters) $recipients = array(); $pager = new KalturaFilterPager(); $pager->pageSize = 500; - //List categoryKusers - $categoryUserList = KBatchBase::$kClient->categoryUser->listAction($this->recipientJobData->categoryUserFilter, $pager); - if (!count($categoryUserList->objects)) - return $recipients; - + $pager->pageIndex = 1; $categoryUserIds = array(); - foreach ($categoryUserList->objects as $categoryUser) - $categoryUserIds[] = $categoryUser->userId; - + $maxPagesToScan = 2; + do + { + $categoryUserList = KBatchBase::$kClient->categoryUser->listAction($this->recipientJobData->categoryUserFilter, $pager); + foreach ($categoryUserList->objects as $categoryUser) + $categoryUserIds[] = $categoryUser->userId; + + $pager->pageIndex ++; + } + while (($pager->pageSize == count($categoryUserList->objects)) and ($pager->pageIndex <= $maxPagesToScan)); + + if (count($categoryUserIds)==0) + return $recipients; + + $pager->pageIndex = 1; $userFilter = new KalturaUserFilter(); $userFilter->idIn = implode(',', $categoryUserIds); - $userList = KBatchBase::$kClient->user->listAction($userFilter, $pager); - foreach ($userList->objects as $user) + do { - /* @var $user KalturaUser */ - $recipients[$user->email] = $user->firstName. ' ' . $user->lastName; + $userList = KBatchBase::$kClient->user->listAction($userFilter, $pager); + foreach ($userList->objects as $user) + $recipients[$user->email] = $user->firstName. ' ' . $user->lastName; + + $pager->pageIndex ++; } + while ($pager->pageSize == count($userList->objects)); return $recipients; } -} \ No newline at end of file +} diff --git a/plugins/kontiki/lib/model/data/kKontikiStorageExportJobData.php b/plugins/kontiki/lib/model/data/kKontikiStorageExportJobData.php index 3a2dc34fb4a..49574e5aab6 100644 --- a/plugins/kontiki/lib/model/data/kKontikiStorageExportJobData.php +++ b/plugins/kontiki/lib/model/data/kKontikiStorageExportJobData.php @@ -54,7 +54,7 @@ public function getServiceToken() return $this->serviceToken; } - public function setStorageExportJobData(StorageProfile $externalStorage, FileSync $fileSync, $srcFileSyncLocalPath, $force = false) + public function setStorageExportJobData(StorageProfile $externalStorage, FileSync $fileSync, $srcFileSync, $force = false) { /* @var $externalStorage KontikiStorageProfile */ $this->setServerUrl($externalStorage->getStorageUrl()); diff --git a/plugins/metadata/batch/Transform/KAsyncTransformMetadata.class.php b/plugins/metadata/batch/Transform/KAsyncTransformMetadata.class.php index 5e94fea70eb..a2a0bbc1374 100644 --- a/plugins/metadata/batch/Transform/KAsyncTransformMetadata.class.php +++ b/plugins/metadata/batch/Transform/KAsyncTransformMetadata.class.php @@ -104,7 +104,8 @@ private function upgrade(KalturaBatchJob $job, KalturaTransformMetadataJobData $ foreach($transformList->objects as $object) { /* @var $object KalturaMetadata */ - $xml = kXsd::transformXmlData($object->xml, $data->destXsdPath, $data->srcXslPath); + $xslStr = kEncryptFileUtils::getEncryptedFileContent($data->srcXsl->filePath, $data->srcXsl->encryptionKey, self::getIV()); + $xml = kXsd::transformXmlData($object->xml, $data->destXsdPath, $xslStr); if($xml) { self::$kClient->metadata->update($object->id, $xml, $object->version); diff --git a/plugins/metadata/lib/api/KalturaTransformMetadataJobData.php b/plugins/metadata/lib/api/KalturaTransformMetadataJobData.php index 2adf6f60ed1..8d84fe67549 100644 --- a/plugins/metadata/lib/api/KalturaTransformMetadataJobData.php +++ b/plugins/metadata/lib/api/KalturaTransformMetadataJobData.php @@ -6,9 +6,9 @@ class KalturaTransformMetadataJobData extends KalturaJobData { /** - * @var string + * @var KalturaFileContainer */ - public $srcXslPath; + public $srcXsl; /** * @var int @@ -32,7 +32,7 @@ class KalturaTransformMetadataJobData extends KalturaJobData private static $map_between_objects = array ( - "srcXslPath" , + "srcXsl" , "srcVersion" , "destVersion" , "metadataProfileId" , diff --git a/plugins/metadata/lib/batch/model/kTransformMetadataJobData.php b/plugins/metadata/lib/batch/model/kTransformMetadataJobData.php index 0a7ed74f75b..dfd38956e9f 100644 --- a/plugins/metadata/lib/batch/model/kTransformMetadataJobData.php +++ b/plugins/metadata/lib/batch/model/kTransformMetadataJobData.php @@ -6,9 +6,9 @@ class kTransformMetadataJobData extends kJobData { /** - * @var string + * @var FileContainer */ - private $srcXslPath; + private $srcXsl; /** * @var int @@ -32,11 +32,11 @@ class kTransformMetadataJobData extends kJobData /** - * @return the $srcXslPath + * @return FileContainer $srcXsl */ - public function getSrcXslPath() + public function getSrcXsl() { - return $this->srcXslPath; + return $this->srcXsl; } /** @@ -64,11 +64,11 @@ public function getMetadataProfileId() } /** - * @param $srcXslPath the $srcXslPath to set + * @param FileContainer $srcXsl */ - public function setSrcXslPath($srcXslPath) + public function setSrcXsl($srcXsl) { - $this->srcXslPath = $srcXslPath; + $this->srcXsl = $srcXsl; } /** diff --git a/plugins/metadata/lib/kMetadataFlowManager.php b/plugins/metadata/lib/kMetadataFlowManager.php index aaa5d4ab479..db23e770dd9 100644 --- a/plugins/metadata/lib/kMetadataFlowManager.php +++ b/plugins/metadata/lib/kMetadataFlowManager.php @@ -44,7 +44,7 @@ protected function updatedTransformMetadata(BatchJob $dbBatchJob, kTransformMeta protected function updatedTransformMetadataPending(BatchJob $dbBatchJob, kTransformMetadataJobData $data) { - if($data->getSrcXslPath()) + if($data->getSrcXsl()) { $metadataProfile = MetadataProfilePeer::retrieveByPK($data->getMetadataProfileId()); if($metadataProfile) @@ -59,7 +59,7 @@ protected function updatedTransformMetadataPending(BatchJob $dbBatchJob, kTransf protected function updatedTransformMetadataFinished(BatchJob $dbBatchJob, kTransformMetadataJobData $data) { - if($data->getSrcXslPath()) + if($data->getSrcXsl()) { $metadataProfile = MetadataProfilePeer::retrieveByPK($data->getMetadataProfileId()); if($metadataProfile) @@ -81,7 +81,7 @@ protected function updatedTransformMetadataFailed(BatchJob $dbBatchJob, kTransfo if(!$metadataProfile) return $dbBatchJob; - if($data->getSrcXslPath()) + if($data->getSrcXsl()) { $metadataProfile->setStatus(MetadataProfile::STATUS_DEPRECATED); $metadataProfile->save(); diff --git a/plugins/metadata/lib/kMetadataManager.php b/plugins/metadata/lib/kMetadataManager.php index bb4c5c35d7e..ba2f36442ba 100644 --- a/plugins/metadata/lib/kMetadataManager.php +++ b/plugins/metadata/lib/kMetadataManager.php @@ -690,9 +690,7 @@ private static function addTransformMetadataJob($partnerId, $metadataProfileId, $job->save(); $key = $job->getSyncKey(BatchJob::FILE_SYNC_BATCHJOB_SUB_TYPE_CONFIG); kFileSyncUtils::file_put_contents($key, $xsl); - - $xslPath = kFileSyncUtils::getLocalFilePathForKey($key); - $data->setSrcXslPath($xslPath); + $data->setSrcXsl(kJobsManager::getFileContainer($key)); } $data->setMetadataProfileId($metadataProfileId); diff --git a/plugins/search/providers/elastic_search/config/mapping/category_mapping.json b/plugins/search/providers/elastic_search/config/mapping/category_mapping.json index 8d5662162d5..ec1b612a704 100644 --- a/plugins/search/providers/elastic_search/config/mapping/category_mapping.json +++ b/plugins/search/providers/elastic_search/config/mapping/category_mapping.json @@ -8,6 +8,16 @@ "type": "pattern_replace", "pattern": "(\\s+)", "replacement": " " + }, + "kaltura_special_chars_filter": { + "type": "mapping", + "mappings": [ + "'=>", + "`=>", + "‘=>", + "^=>", + "~=>" + ] } }, "tokenizer": { @@ -25,9 +35,8 @@ "kaltura_ngrams": { "type": "custom", "tokenizer": "kaltura_ngram_tokenizer", - "filter": [ - "lowercase" - ] + "char_filter": ["kaltura_special_chars_filter"], + "filter": ["lowercase"] }, "kaltura_keyword": { "type": "custom", @@ -43,6 +52,7 @@ }, "kaltura_text" : { "tokenizer" : "standard", + "char_filter": ["kaltura_special_chars_filter"], "filter" : ["standard", "lowercase", "asciifolding"] } } @@ -53,6 +63,9 @@ "_source" : { "enabled" : true }, + "_all": { + "enabled": false + }, "properties" : { "partner_id" : { "type" : "text", diff --git a/plugins/search/providers/elastic_search/config/mapping/entry_mapping.json b/plugins/search/providers/elastic_search/config/mapping/entry_mapping.json index 57689882a39..69ffab9b37b 100644 --- a/plugins/search/providers/elastic_search/config/mapping/entry_mapping.json +++ b/plugins/search/providers/elastic_search/config/mapping/entry_mapping.json @@ -31,7 +31,17 @@ "type": "pattern_replace", "pattern": "(\\s+)", "replacement": " " - } + }, + "kaltura_special_chars_filter": { + "type": "mapping", + "mappings": [ + "'=>", + "`=>", + "‘=>", + "^=>", + "~=>" + ] + } }, "tokenizer": { "kaltura_ngram_tokenizer": { @@ -52,16 +62,13 @@ "kaltura_ngrams": { "type": "custom", "tokenizer": "kaltura_ngram_tokenizer", - "filter": [ - "lowercase" - ] + "char_filter": ["kaltura_special_chars_filter"], + "filter": ["lowercase"] }, "kaltura_keyword": { "type": "custom", "tokenizer": "keyword", - "char_filter": [ - "kaltura_whitespace_filter" - ], + "char_filter": ["kaltura_whitespace_filter"], "filter": [ "lowercase", "trim", @@ -69,8 +76,9 @@ ] }, "kaltura_text" : { - "tokenizer" : "standard", - "filter" : ["standard", "lowercase", "asciifolding"] + "tokenizer": "standard", + "char_filter": ["kaltura_special_chars_filter"], + "filter": ["standard", "lowercase", "asciifolding"] }, "kaltura_english_synonym": { "tokenizer": "standard", @@ -102,6 +110,9 @@ "_source" : { "enabled" : true }, + "_all": { + "enabled": false + }, "properties" : { "name" : { "type" : "text", diff --git a/plugins/search/providers/elastic_search/config/mapping/kuser_mapping.json b/plugins/search/providers/elastic_search/config/mapping/kuser_mapping.json index 7de67aff056..bd480a80d59 100644 --- a/plugins/search/providers/elastic_search/config/mapping/kuser_mapping.json +++ b/plugins/search/providers/elastic_search/config/mapping/kuser_mapping.json @@ -8,6 +8,16 @@ "type": "pattern_replace", "pattern": "(\\s+)", "replacement": " " + }, + "kaltura_special_chars_filter": { + "type": "mapping", + "mappings": [ + "'=>", + "`=>", + "‘=>", + "^=>", + "~=>" + ] } }, "tokenizer": { @@ -25,9 +35,8 @@ "kaltura_ngrams": { "type": "custom", "tokenizer": "kaltura_ngram_tokenizer", - "filter": [ - "lowercase" - ] + "char_filter": ["kaltura_special_chars_filter"], + "filter": ["lowercase"] }, "kaltura_keyword": { "type": "custom", @@ -43,6 +52,7 @@ }, "kaltura_text" : { "tokenizer" : "standard", + "char_filter": ["kaltura_special_chars_filter"], "filter" : ["standard", "lowercase", "asciifolding"] } } @@ -53,6 +63,9 @@ "_source" : { "enabled" : true }, + "_all": { + "enabled": false + }, "properties" : { "group_ids" : { "type" : "text", diff --git a/plugins/search/providers/elastic_search/lib/api/types/items/KalturaESearchCuePointItem.php b/plugins/search/providers/elastic_search/lib/api/types/items/KalturaESearchCuePointItem.php index 6f09087d821..e1d86274f84 100644 --- a/plugins/search/providers/elastic_search/lib/api/types/items/KalturaESearchCuePointItem.php +++ b/plugins/search/providers/elastic_search/lib/api/types/items/KalturaESearchCuePointItem.php @@ -11,13 +11,17 @@ class KalturaESearchCuePointItem extends KalturaESearchItem */ public $fieldName; + /** + * @var KalturaCuePointType + */ + public $cuePointType; + private static $map_between_objects = array( - 'fieldName' + 'fieldName', + 'cuePointType', ); - private static $map_dynamic_enum = array( - KalturaESearchCuePointFieldName::CUE_POINT_TYPE => 'KalturaCuePointType' - ); + private static $map_dynamic_enum = array(); protected function getMapBetweenObjects() { diff --git a/plugins/search/providers/elastic_search/lib/api/types/items/KalturaESearchEntryItem.php b/plugins/search/providers/elastic_search/lib/api/types/items/KalturaESearchEntryItem.php index a4f2aa63fba..256a024af66 100644 --- a/plugins/search/providers/elastic_search/lib/api/types/items/KalturaESearchEntryItem.php +++ b/plugins/search/providers/elastic_search/lib/api/types/items/KalturaESearchEntryItem.php @@ -6,6 +6,8 @@ class KalturaESearchEntryItem extends KalturaESearchItem { + const KUSER_ID_THAT_DOESNT_EXIST = -1; + /** * @var KalturaESearchEntryFieldName */ @@ -34,12 +36,12 @@ public function toObject($object_to_fill = null, $props_to_skip = array()) if(in_array($this->fieldName, array(KalturaESearchEntryFieldName::ENTRY_USER_ID, KalturaESearchEntryFieldName::ENTRY_ENTITLED_USER_EDIT, KalturaESearchEntryFieldName::ENTRY_ENTITLED_USER_PUBLISH, KalturaESearchEntryFieldName::ENTRY_CREATOR_ID))) { + $kuserId = self::KUSER_ID_THAT_DOESNT_EXIST; $kuser = kuserPeer::getKuserByPartnerAndUid(kCurrentContext::getCurrentPartnerId(), $this->searchTerm, true); - if(!$kuser) - { - throw new KalturaAPIException(KalturaErrors::INVALID_USER_ID); - } - $this->searchTerm = $kuser->getId(); + if($kuser) + $kuserId = $kuser->getId(); + + $this->searchTerm = $kuserId; } return parent::toObject($object_to_fill, $props_to_skip); diff --git a/plugins/search/providers/elastic_search/lib/api/types/items/KalturaESearchHighlight.php b/plugins/search/providers/elastic_search/lib/api/types/items/KalturaESearchHighlight.php new file mode 100644 index 00000000000..f3337ca06d2 --- /dev/null +++ b/plugins/search/providers/elastic_search/lib/api/types/items/KalturaESearchHighlight.php @@ -0,0 +1,35 @@ +fromObject($obj, $responseProfile); + $newArr[] = $nObj; + } + + return $newArr; + } +} diff --git a/plugins/search/providers/elastic_search/lib/api/types/items/KalturaESearchItemData.php b/plugins/search/providers/elastic_search/lib/api/types/items/KalturaESearchItemData.php index 928e9a30d92..48f0d985b94 100644 --- a/plugins/search/providers/elastic_search/lib/api/types/items/KalturaESearchItemData.php +++ b/plugins/search/providers/elastic_search/lib/api/types/items/KalturaESearchItemData.php @@ -5,9 +5,8 @@ */ abstract class KalturaESearchItemData extends KalturaObject { - /** - * @var string + * @var KalturaESearchHighlightArray */ public $highlight; diff --git a/plugins/search/providers/elastic_search/lib/api/types/results/KalturaESearchResult.php b/plugins/search/providers/elastic_search/lib/api/types/results/KalturaESearchResult.php index 4d3ae537c47..838e01fdfe4 100644 --- a/plugins/search/providers/elastic_search/lib/api/types/results/KalturaESearchResult.php +++ b/plugins/search/providers/elastic_search/lib/api/types/results/KalturaESearchResult.php @@ -11,7 +11,7 @@ abstract class KalturaESearchResult extends KalturaObject public $object; /** - * @var string + * @var KalturaESearchHighlightArray */ public $highlight; diff --git a/plugins/search/providers/elastic_search/lib/entitlement/conditions/kElasticBaseEntitlementCondition.php b/plugins/search/providers/elastic_search/lib/entitlement/conditions/kElasticBaseEntitlementCondition.php deleted file mode 100644 index dd9810e8c9a..00000000000 --- a/plugins/search/providers/elastic_search/lib/entitlement/conditions/kElasticBaseEntitlementCondition.php +++ /dev/null @@ -1,27 +0,0 @@ - array( - "{$fieldPrefix}_id" => $params['entryIds'] - ) - ) - ); - return $conditions; - } - - public static function applyCondition(&$entryQuery, &$parentEntryQuery) - { - $params['entryIds'] = kEntryElasticEntitlement::$entriesDisabledEntitlement; - if($parentEntryQuery) - { - $conditions = self::getEntitlementCondition($params, 'parent_entry.entry'); - self::attachToQuery($parentEntryQuery, 'should', $conditions); - $parentEntryQuery['minimum_should_match'] = 1; - } - $conditions = self::getEntitlementCondition($params); - self::attachToQuery($entryQuery, 'should', $conditions); - $entryQuery['minimum_should_match'] = 1; - } - - public static function shouldContribute() - { - if(kEntryElasticEntitlement::$entriesDisabledEntitlement && count(kEntryElasticEntitlement::$entriesDisabledEntitlement)) - return true; - - return false; - } -} diff --git a/plugins/search/providers/elastic_search/lib/entitlement/conditions/kElasticPublicEntriesEntitlementCondition.php b/plugins/search/providers/elastic_search/lib/entitlement/conditions/kElasticPublicEntriesEntitlementCondition.php deleted file mode 100644 index ee2f71e7ed0..00000000000 --- a/plugins/search/providers/elastic_search/lib/entitlement/conditions/kElasticPublicEntriesEntitlementCondition.php +++ /dev/null @@ -1,61 +0,0 @@ - array( - 'must_not' => array( - 'exists' => array( - 'field' => "{$fieldPrefix}category_ids" - ) - ) - ) - ) - ); - return $conditions; - } - - public static function applyCondition(&$entryQuery, &$parentEntryQuery) - { - if(kEntryElasticEntitlement::$publicEntries) - { - if($parentEntryQuery) - { - $conditions = self::getEntitlementCondition(array(), 'parent_entry.'); - self::attachToQuery($parentEntryQuery, 'should', $conditions); - $parentEntryQuery['minimum_should_match'] = 1; - } - $conditions = self::getEntitlementCondition(); - self::attachToQuery($entryQuery, 'should', $conditions); - $entryQuery['minimum_should_match'] = 1; - } - - if(kEntryElasticEntitlement::$publicActiveEntries) - { - if($parentEntryQuery) - { - $conditions = self::getEntitlementCondition(array(), 'parent_entry.active_'); - self::attachToQuery($parentEntryQuery, 'should', $conditions); - $parentEntryQuery['minimum_should_match'] = 1; - } - $conditions = self::getEntitlementCondition(array(), 'active_'); - self::attachToQuery($entryQuery, 'should', $conditions); - $entryQuery['minimum_should_match'] = 1; - } - } - - public static function shouldContribute() - { - if(kEntryElasticEntitlement::$publicEntries || kEntryElasticEntitlement::$publicActiveEntries) - return true; - - return false; - } -} diff --git a/plugins/search/providers/elastic_search/lib/entitlement/conditions/kElasticUserCategoryEntryEntitlementCondition.php b/plugins/search/providers/elastic_search/lib/entitlement/conditions/kElasticUserCategoryEntryEntitlementCondition.php deleted file mode 100644 index f0788eeec4a..00000000000 --- a/plugins/search/providers/elastic_search/lib/entitlement/conditions/kElasticUserCategoryEntryEntitlementCondition.php +++ /dev/null @@ -1,146 +0,0 @@ - array( - "{$fieldPrefix}category_ids" => $params['category_ids'] - ) - ) - ); - return $conditions; - } - - public static function applyCondition(&$entryQuery, &$parentEntryQuery) - { - $kuserId = kEntryElasticEntitlement::$kuserId; - if(!$kuserId) - { - KalturaLog::log('cannot add userCategory to entry entitlement to elastic without a kuserId - setting kuser id to -1'); - $kuserId = -1; - } - //get category ids with $privacyContext - $categories = self::getUserCategories($kuserId, kEntryElasticEntitlement::$privacyContext, kEntryElasticEntitlement::$privacy); - if(count($categories) == 0) - $categories = array(category::CATEGORY_ID_THAT_DOES_NOT_EXIST); - - $params['category_ids'] = $categories; - - if($parentEntryQuery) - { - $conditions = self::getEntitlementCondition($params, 'parent_entry.'); - self::attachToQuery($parentEntryQuery, 'should', $conditions); - $parentEntryQuery['minimum_should_match'] = 1; - } - $conditions = self::getEntitlementCondition($params); - self::attachToQuery($entryQuery, 'should', $conditions); - $entryQuery['minimum_should_match'] = 1; - } - - public static function shouldContribute() - { - if(kEntryElasticEntitlement::$userCategoryToEntryEntitlement || kEntryElasticEntitlement::$entryInSomeCategoryNoPC) - return true; - - return false; - } - - protected static function getUserCategories($kuserId, $privacyContext = null, $privacy = null) - { - $params = array( - 'index' => ElasticIndexMap::ELASTIC_CATEGORY_INDEX, - 'type' => ElasticIndexMap::ELASTIC_CATEGORY_TYPE, - 'size' => self::MAX_CATEGORIES - ); - - $body = array( - 'query' => array( - 'bool' => array( - 'filter' => array( - array( - 'term' => array( - 'partner_status' => elasticSearchUtils::formatPartnerStatus(kEntryElasticEntitlement::$partnerId, CategoryStatus::ACTIVE) - ) - ), - array( - 'bool' => array( - 'should' => array( - array( - 'terms' => array( - 'kuser_ids' => array( - 'index' => ElasticIndexMap::ELASTIC_KUSER_INDEX, - 'type' => ElasticIndexMap::ELASTIC_KUSER_TYPE, - 'id' => $kuserId, - 'path' => 'group_ids' - ) - ) - ), - array( - 'term' => array( - 'kuser_ids' => $kuserId - ) - ) - ), - 'minimum_should_match' => 1 - ) - ) - ) - ) - ) - ); - - $body['_source'] = false; - - if(kEntryElasticEntitlement::$entryInSomeCategoryNoPC) - { - $body['query']['bool']['filter'][1]['bool']['should'][] = array( - 'bool' => array( - 'must_not' => array( - 'exists' => array( - 'field' => 'privacy_context' - ) - ) - ) - ); - } - - $privacyContexts = null; - if (!$privacyContext || trim($privacyContext) == '') - $privacyContexts = array(kEntitlementUtils::getDefaultContextString(kEntryElasticEntitlement::$partnerId)); - else - { - $privacyContexts = explode(',', $privacyContext); - $privacyContexts = kEntitlementUtils::addPrivacyContextsPrefix( $privacyContexts, kEntryElasticEntitlement::$partnerId ); - } - - $privacyContexts = array_map('elasticSearchUtils::formatSearchTerm', $privacyContexts); - $body['query']['bool']['filter'][] = array('terms' => array('privacy_contexts' => $privacyContexts)); - - if($privacy) //privacy is an array - { - $privacy = array_map('elasticSearchUtils::formatSearchTerm', $privacy); - $body['query']['bool']['filter'][1]['bool']['should'][] = array('terms' => array('privacy' => $privacy)); - } - - $params['body'] = $body; - $elasticClient = new elasticClient(); - $results = $elasticClient->search($params); - $categories = $results['hits']['hits']; - $categoryIds = array(); - - foreach ($categories as $category) - { - $categoryIds[] = $category['_id']; - } - return $categoryIds; - } -} diff --git a/plugins/search/providers/elastic_search/lib/entitlement/conditions/kElasticUserEntitlementCondition.php b/plugins/search/providers/elastic_search/lib/entitlement/conditions/kElasticUserEntitlementCondition.php deleted file mode 100644 index 348b49afe5e..00000000000 --- a/plugins/search/providers/elastic_search/lib/entitlement/conditions/kElasticUserEntitlementCondition.php +++ /dev/null @@ -1,81 +0,0 @@ - array( - "{$fieldPrefix}entitled_kusers_edit" => array( - 'index' => ElasticIndexMap::ELASTIC_KUSER_INDEX, - 'type' => ElasticIndexMap::ELASTIC_KUSER_TYPE, - 'id' => $params['kuserId'], - 'path' => 'group_ids' - ) - ) - ), - array( - 'term' => array( - "{$fieldPrefix}entitled_kusers_edit" => $params['kuserId'], - ) - ), - array( - 'terms' => array( - "{$fieldPrefix}entitled_kusers_publish" => array( - 'index' => ElasticIndexMap::ELASTIC_KUSER_INDEX, - 'type' => ElasticIndexMap::ELASTIC_KUSER_TYPE, - 'id' => $params['kuserId'], - 'path' => 'group_ids' - ) - ) - ), - array( - 'term' => array( - "{$fieldPrefix}entitled_kusers_publish" => $params['kuserId'], - ) - ), - array( - 'term' => array( - "{$fieldPrefix}kuser_id" => $params['kuserId'] - ) - ) - ); - - return $conditions; - } - - public static function applyCondition(&$entryQuery, &$parentEntryQuery) - { - $kuserId = kEntryElasticEntitlement::$kuserId; - if(!$kuserId) - { - KalturaLog::log('cannot add user entitlement to elastic without a kuserId - setting kuser id to -1'); - $kuserId = -1; - } - $params['kuserId'] = $kuserId; - - if($parentEntryQuery) - { - //add parent conditions - $conditions = self::getEntitlementCondition($params, 'parent_entry.'); - self::attachToQuery($parentEntryQuery, 'should', $conditions); - $parentEntryQuery['minimum_should_match'] = 1; - } - $conditions = self::getEntitlementCondition($params); - self::attachToQuery($entryQuery, 'should', $conditions); - $entryQuery['minimum_should_match'] = 1; - } - - public static function shouldContribute() - { - if(kEntryElasticEntitlement::$userEntitlement) - return true; - - return false; - } -} diff --git a/plugins/search/providers/elastic_search/lib/entitlement/contributors/IKalturaESearchEntryEntitlementDecorator.php b/plugins/search/providers/elastic_search/lib/entitlement/contributors/IKalturaESearchEntryEntitlementDecorator.php new file mode 100644 index 00000000000..7f0b142d5fa --- /dev/null +++ b/plugins/search/providers/elastic_search/lib/entitlement/contributors/IKalturaESearchEntryEntitlementDecorator.php @@ -0,0 +1,12 @@ +addToShould($conditions); + } + $conditions = self::getEntitlementCondition($params); + $entryQuery->addToShould($conditions); + } +} diff --git a/plugins/search/providers/elastic_search/lib/entitlement/contributors/entry/kElasticPublicEntriesEntitlementDecorator.php b/plugins/search/providers/elastic_search/lib/entitlement/contributors/entry/kElasticPublicEntriesEntitlementDecorator.php new file mode 100644 index 00000000000..95194260695 --- /dev/null +++ b/plugins/search/providers/elastic_search/lib/entitlement/contributors/entry/kElasticPublicEntriesEntitlementDecorator.php @@ -0,0 +1,50 @@ +addToMustNot($existQuery); + return $condition; + } + + public static function applyCondition(&$entryQuery, &$parentEntryQuery) + { + if(kEntryElasticEntitlement::$publicEntries) + { + if($parentEntryQuery) + { + $condition = self::getEntitlementCondition(array(), 'parent_entry.'); + $parentEntryQuery->addToShould($condition); + } + $condition = self::getEntitlementCondition(); + $entryQuery->addToShould($condition); + } + + if(kEntryElasticEntitlement::$publicActiveEntries) + { + if($parentEntryQuery) + { + $condition = self::getEntitlementCondition(array(), 'parent_entry.active_'); + $parentEntryQuery->addToShould($condition); + } + $condition = self::getEntitlementCondition(array(), 'active_'); + $entryQuery->addToShould($condition); + } + } +} diff --git a/plugins/search/providers/elastic_search/lib/entitlement/contributors/entry/kElasticUserCategoryEntryEntitlementDecorator.php b/plugins/search/providers/elastic_search/lib/entitlement/contributors/entry/kElasticUserCategoryEntryEntitlementDecorator.php new file mode 100644 index 00000000000..cc8983708cf --- /dev/null +++ b/plugins/search/providers/elastic_search/lib/entitlement/contributors/entry/kElasticUserCategoryEntryEntitlementDecorator.php @@ -0,0 +1,121 @@ +addToShould($condition); + } + + $condition = self::getEntitlementCondition($params); + $entryQuery->addToShould($condition); + } + + private static function getUserCategories($kuserId, $privacyContext = null, $privacy = null) + { + $params = array( + 'index' => ElasticIndexMap::ELASTIC_CATEGORY_INDEX, + 'type' => ElasticIndexMap::ELASTIC_CATEGORY_TYPE, + 'size' => self::MAX_CATEGORIES + ); + $body = array(); + $body['_source'] = false; + + $mainBool = new kESearchBoolQuery(); + $partnerStatus = elasticSearchUtils::formatPartnerStatus(kEntryElasticEntitlement::$partnerId, CategoryStatus::ACTIVE); + $partnerStatusQuery = new kESearchTermQuery('partner_status', $partnerStatus); + $mainBool->addToFilter($partnerStatusQuery); + + $conditionsBoolQuery = new kESearchBoolQuery(); + + $userGroupsQuery = new kESearchTermsQuery('kuser_ids',array( + 'index' => ElasticIndexMap::ELASTIC_KUSER_INDEX, + 'type' => ElasticIndexMap::ELASTIC_KUSER_TYPE, + 'id' => $kuserId, + 'path' => 'group_ids' + )); + $conditionsBoolQuery->addToShould($userGroupsQuery); + $userQuery = new kESearchTermQuery('kuser_ids', $kuserId); + $conditionsBoolQuery->addToShould($userQuery); + + if(kEntryElasticEntitlement::$entryInSomeCategoryNoPC) + { + $noPcQuery = new kESearchBoolQuery(); + $pcExistQuery = new kESearchExistsQuery('privacy_context'); + $noPcQuery->addToMustNot($pcExistQuery); + $conditionsBoolQuery->addToShould($noPcQuery); + } + + $privacyContexts = null; + if (!$privacyContext || trim($privacyContext) == '') + $privacyContexts = array(kEntitlementUtils::getDefaultContextString(kEntryElasticEntitlement::$partnerId)); + else + { + $privacyContexts = explode(',', $privacyContext); + $privacyContexts = kEntitlementUtils::addPrivacyContextsPrefix( $privacyContexts, kEntryElasticEntitlement::$partnerId ); + } + + $privacyContexts = array_map('elasticSearchUtils::formatSearchTerm', $privacyContexts); + $privacyContextsQuery = new kESearchTermsQuery('privacy_contexts',$privacyContexts); + $mainBool->addToFilter($privacyContextsQuery); + + if($privacy) //privacy is an array + { + $privacy = array_map('elasticSearchUtils::formatSearchTerm', $privacy); + $privacyQuery = new kESearchTermsQuery('privacy', $privacy); + $conditionsBoolQuery->addToShould($privacyQuery); + } + + $mainBool->addToFilter($conditionsBoolQuery); + $body['query'] = $mainBool->getFinalQuery(); + $params['body'] = $body; + + $elasticClient = new elasticClient(); + $results = $elasticClient->search($params); + $categories = $results['hits']['hits']; + $categoryIds = array(); + + foreach ($categories as $category) + { + $categoryIds[] = $category['_id']; + } + return $categoryIds; + } + +} diff --git a/plugins/search/providers/elastic_search/lib/entitlement/contributors/entry/kElasticUserEntitlementDecorator.php b/plugins/search/providers/elastic_search/lib/entitlement/contributors/entry/kElasticUserEntitlementDecorator.php new file mode 100644 index 00000000000..8fe48793375 --- /dev/null +++ b/plugins/search/providers/elastic_search/lib/entitlement/contributors/entry/kElasticUserEntitlementDecorator.php @@ -0,0 +1,66 @@ + ElasticIndexMap::ELASTIC_KUSER_INDEX,'type' => ElasticIndexMap::ELASTIC_KUSER_TYPE, + 'id' => $params['kuserId'], 'path' => 'group_ids')); + $conditions[] = $userEditPreFetchGroupCondition; + $userEditCondition = new kESearchTermQuery("{$fieldPrefix}entitled_kusers_edit",$params['kuserId']); + $conditions[] = $userEditCondition; + + $userPublishPreFetchGroupCondition = new kESearchTermsQuery("{$fieldPrefix}entitled_kusers_publish", + array('index' => ElasticIndexMap::ELASTIC_KUSER_INDEX,'type' => ElasticIndexMap::ELASTIC_KUSER_TYPE, + 'id' => $params['kuserId'], 'path' => 'group_ids')); + $conditions[] = $userPublishPreFetchGroupCondition; + $userPublishCondition = new kESearchTermQuery("{$fieldPrefix}entitled_kusers_publish",$params['kuserId']); + $conditions[] = $userPublishCondition; + + $userCondition = new kESearchTermQuery("{$fieldPrefix}kuser_id",$params['kuserId']); + $conditions[] = $userCondition; + return $conditions; + } + + public static function applyCondition(&$entryQuery, &$parentEntryQuery) + { + $kuserId = kEntryElasticEntitlement::$kuserId; + if(!$kuserId) + { + KalturaLog::log('cannot add user entitlement to elastic without a kuserId - setting kuser id to -1'); + $kuserId = -1; + } + $params['kuserId'] = $kuserId; + + if($parentEntryQuery) + { + //add parent conditions + $conditions = self::getEntitlementCondition($params, 'parent_entry.'); + foreach ($conditions as $condition) + { + $parentEntryQuery->addToShould($condition); + } + } + $conditions = self::getEntitlementCondition($params); + foreach ($conditions as $condition) + { + $entryQuery->addToShould($condition); + } + } +} diff --git a/plugins/search/providers/elastic_search/lib/entitlement/kBaseElasticEntitlement.php b/plugins/search/providers/elastic_search/lib/entitlement/kBaseElasticEntitlement.php index 5c5cf04021c..20cf2b863db 100644 --- a/plugins/search/providers/elastic_search/lib/entitlement/kBaseElasticEntitlement.php +++ b/plugins/search/providers/elastic_search/lib/entitlement/kBaseElasticEntitlement.php @@ -10,6 +10,8 @@ abstract class kBaseElasticEntitlement public static $partnerId; public static $ks; + protected static $entitlementContributors = array(); + public static function init() { if(!self::$isInitialized) @@ -21,5 +23,10 @@ protected static function initialize() self::$ks = ks::fromSecureString(kCurrentContext::$ks); self::$partnerId = kCurrentContext::$partner_id ? kCurrentContext::$partner_id : kCurrentContext::$ks_partner_id; } - + + public static function getEntitlementContributors() + { + return static::$entitlementContributors; + } + } diff --git a/plugins/search/providers/elastic_search/lib/entitlement/kEntryElasticEntitlement.php b/plugins/search/providers/elastic_search/lib/entitlement/kEntryElasticEntitlement.php index 4a31874cbcb..e78a2c99e41 100644 --- a/plugins/search/providers/elastic_search/lib/entitlement/kEntryElasticEntitlement.php +++ b/plugins/search/providers/elastic_search/lib/entitlement/kEntryElasticEntitlement.php @@ -18,6 +18,13 @@ class kEntryElasticEntitlement extends kBaseElasticEntitlement public static $parentEntitlement = false; public static $entryInSomeCategoryNoPC = false; //active + pending + protected static $entitlementContributors = array( + 'kElasticEntryDisableEntitlementDecorator', + 'kElasticPublicEntriesEntitlementDecorator', + 'kElasticUserCategoryEntryEntitlementDecorator', + 'kElasticUserEntitlementDecorator', + ); + protected static function initialize() { parent::initialize(); diff --git a/plugins/search/providers/elastic_search/lib/model/ESearchHighlight.php b/plugins/search/providers/elastic_search/lib/model/ESearchHighlight.php new file mode 100644 index 00000000000..9f3acad17f7 --- /dev/null +++ b/plugins/search/providers/elastic_search/lib/model/ESearchHighlight.php @@ -0,0 +1,50 @@ +fieldName; + } + + /** + * @param string $fieldName + */ + public function setFieldName($fieldName) + { + $this->fieldName = $fieldName; + } + + /** + * @return array + */ + public function getHits() + { + return $this->hits; + } + + /** + * @param array $hits + */ + public function setHits($hits) + { + $this->hits = $hits; + } +} \ No newline at end of file diff --git a/plugins/search/providers/elastic_search/lib/model/ESearchResult.php b/plugins/search/providers/elastic_search/lib/model/ESearchResult.php index c5680d4465c..abba2b8f159 100644 --- a/plugins/search/providers/elastic_search/lib/model/ESearchResult.php +++ b/plugins/search/providers/elastic_search/lib/model/ESearchResult.php @@ -17,7 +17,7 @@ class ESearchResult extends BaseObject protected $itemsData; /** - * @var string + * @var array */ protected $highlight; @@ -54,7 +54,7 @@ public function setItemsData($itemsData) } /** - * @param string + * @param array */ public function setHighlight($highlight) { @@ -62,7 +62,7 @@ public function setHighlight($highlight) } /** - * @return string + * @return array */ public function getHighlight() { diff --git a/plugins/search/providers/elastic_search/lib/model/enum/ESearchCuePointFieldName.php b/plugins/search/providers/elastic_search/lib/model/enum/ESearchCuePointFieldName.php index c35f0e95eb8..2bb8597234c 100644 --- a/plugins/search/providers/elastic_search/lib/model/enum/ESearchCuePointFieldName.php +++ b/plugins/search/providers/elastic_search/lib/model/enum/ESearchCuePointFieldName.php @@ -5,7 +5,6 @@ */ interface ESearchCuePointFieldName extends BaseEnum { - const CUE_POINT_TYPE = 'cue_points.cue_point_type'; const CUE_POINT_ID = 'cue_points.cue_point_id'; const CUE_POINT_NAME = 'cue_points.cue_point_name'; const CUE_POINT_TEXT = 'cue_points.cue_point_text'; diff --git a/plugins/search/providers/elastic_search/lib/model/items/ESearchCaptionItem.php b/plugins/search/providers/elastic_search/lib/model/items/ESearchCaptionItem.php index d7e1fd571d9..76c899dd70f 100644 --- a/plugins/search/providers/elastic_search/lib/model/items/ESearchCaptionItem.php +++ b/plugins/search/providers/elastic_search/lib/model/items/ESearchCaptionItem.php @@ -83,37 +83,31 @@ public static function createSearchQuery($eSearchItemsArr, $boolOperator, &$quer return self::createNestedQueryForItems($eSearchItemsArr, $boolOperator, $queryAttributes); } - public static function createSingleItemSearchQuery($eSearchCaptionItem, $boolOperator, &$captionQuery, $allowedSearchTypes, &$queryAttributes) + public static function createSingleItemSearchQuery($eSearchCaptionItem, $boolOperator, &$captionBoolQuery, $allowedSearchTypes, &$queryAttributes) { $eSearchCaptionItem->validateItemInput(); switch ($eSearchCaptionItem->getItemType()) { case ESearchItemType::EXACT_MATCH: - $captionQuery['nested']['query']['bool'][$boolOperator][] = - kESearchQueryManager::getExactMatchQuery($eSearchCaptionItem, $eSearchCaptionItem->getFieldName(), $allowedSearchTypes, $queryAttributes); + $query = kESearchQueryManager::getExactMatchQuery($eSearchCaptionItem, $eSearchCaptionItem->getFieldName(), $allowedSearchTypes, $queryAttributes); break; case ESearchItemType::PARTIAL: - $captionQuery['nested']['query']['bool'][$boolOperator][] = - kESearchQueryManager::getMultiMatchQuery($eSearchCaptionItem, $eSearchCaptionItem->getFieldName(), $queryAttributes); + $query = kESearchQueryManager::getPartialQuery($eSearchCaptionItem, $eSearchCaptionItem->getFieldName(), $queryAttributes); break; case ESearchItemType::STARTS_WITH: - $captionQuery['nested']['query']['bool'][$boolOperator][] = - kESearchQueryManager::getPrefixQuery($eSearchCaptionItem, $eSearchCaptionItem->getFieldName(), $allowedSearchTypes, $queryAttributes); + $query = kESearchQueryManager::getPrefixQuery($eSearchCaptionItem, $eSearchCaptionItem->getFieldName(), $allowedSearchTypes, $queryAttributes); break; case ESearchItemType::EXISTS: - $captionQuery['nested']['query']['bool'][$boolOperator][] = - kESearchQueryManager::getExistsQuery($eSearchCaptionItem, $eSearchCaptionItem->getFieldName(), $allowedSearchTypes, $queryAttributes); + $query = kESearchQueryManager::getExistsQuery($eSearchCaptionItem, $eSearchCaptionItem->getFieldName(), $allowedSearchTypes, $queryAttributes); break; case ESearchItemType::RANGE: - $captionQuery['nested']['query']['bool'][$boolOperator][] = - kESearchQueryManager::getRangeQuery($eSearchCaptionItem, $eSearchCaptionItem->getFieldName(), $allowedSearchTypes, $queryAttributes); + $query = kESearchQueryManager::getRangeQuery($eSearchCaptionItem, $eSearchCaptionItem->getFieldName(), $allowedSearchTypes, $queryAttributes); break; default: KalturaLog::log("Undefined item type[".$eSearchCaptionItem->getItemType()."]"); } - if($boolOperator == 'should') - $captionQuery['nested']['query']['bool']['minimum_should_match'] = 1; + $captionBoolQuery->addByOperatorType($boolOperator, $query); } public function shouldAddLanguageSearch() @@ -129,4 +123,8 @@ public function getItemMappingFieldsDelimiter() return elasticSearchUtils::UNDERSCORE_FIELD_DELIMITER; } + public function getNestedQueryName() + { + return ESearchItemDataType::CAPTION.self::QUERY_NAME_DELIMITER.self::DEFAULT_GROUP_NAME; + } } \ No newline at end of file diff --git a/plugins/search/providers/elastic_search/lib/model/items/ESearchCaptionItemData.php b/plugins/search/providers/elastic_search/lib/model/items/ESearchCaptionItemData.php index e7a96780cc3..fbcafe42aef 100644 --- a/plugins/search/providers/elastic_search/lib/model/items/ESearchCaptionItemData.php +++ b/plugins/search/providers/elastic_search/lib/model/items/ESearchCaptionItemData.php @@ -122,6 +122,7 @@ public function loadFromElasticHits($objectResult) $this->setEndsAt($objectResult['_source']['end_time']); $this->setLanguage($objectResult['_source']['language']); $this->setCaptionAssetId($objectResult['_source']['caption_asset_id']); - $this->setHighlight($objectResult['highlight']); + if(isset($objectResult['highlight'])) + $this->setHighlight($objectResult['highlight']); } } \ No newline at end of file diff --git a/plugins/search/providers/elastic_search/lib/model/items/ESearchCategoryItem.php b/plugins/search/providers/elastic_search/lib/model/items/ESearchCategoryItem.php index 117d47d3bb2..6f0f5d093bb 100644 --- a/plugins/search/providers/elastic_search/lib/model/items/ESearchCategoryItem.php +++ b/plugins/search/providers/elastic_search/lib/model/items/ESearchCategoryItem.php @@ -117,7 +117,7 @@ public static function createSingleItemSearchQuery($categorySearchItem, &$catego $categoryQuery[] = kESearchQueryManager::getExactMatchQuery($categorySearchItem, $categorySearchItem->getFieldName(), $allowedSearchTypes, $queryAttributes); break; case ESearchItemType::PARTIAL: - $categoryQuery[] = kESearchQueryManager::getMultiMatchQuery($categorySearchItem, $categorySearchItem->getFieldName(), $queryAttributes); + $categoryQuery[] = kESearchQueryManager::getPartialQuery($categorySearchItem, $categorySearchItem->getFieldName(), $queryAttributes); break; case ESearchItemType::STARTS_WITH: $categoryQuery[] = kESearchQueryManager::getPrefixQuery($categorySearchItem, $categorySearchItem->getFieldName(), $allowedSearchTypes, $queryAttributes); diff --git a/plugins/search/providers/elastic_search/lib/model/items/ESearchCuePointItem.php b/plugins/search/providers/elastic_search/lib/model/items/ESearchCuePointItem.php index af8d20ef18f..eb470c7dee9 100644 --- a/plugins/search/providers/elastic_search/lib/model/items/ESearchCuePointItem.php +++ b/plugins/search/providers/elastic_search/lib/model/items/ESearchCuePointItem.php @@ -20,8 +20,12 @@ class ESearchCuePointItem extends ESearchNestedObjectItem */ protected $searchTerm; + /** + * @var CuePointType + */ + protected $cuePointType; + private static $allowed_search_types_for_field = array( - 'cue_points.cue_point_type' => array('ESearchItemType::EXACT_MATCH'=> ESearchItemType::EXACT_MATCH), 'cue_points.cue_point_id' => array('ESearchItemType::EXACT_MATCH'=> ESearchItemType::EXACT_MATCH, ESearchUnifiedItem::UNIFIED), 'cue_points.cue_point_name' => array('ESearchItemType::EXACT_MATCH'=> ESearchItemType::EXACT_MATCH, 'ESearchItemType::PARTIAL'=> ESearchItemType::PARTIAL, 'ESearchItemType::STARTS_WITH'=> ESearchItemType::STARTS_WITH, "ESearchItemType::EXISTS"=> ESearchItemType::EXISTS, ESearchUnifiedItem::UNIFIED), 'cue_points.cue_point_text' => array('ESearchItemType::EXACT_MATCH'=> ESearchItemType::EXACT_MATCH, 'ESearchItemType::PARTIAL'=> ESearchItemType::PARTIAL, 'ESearchItemType::STARTS_WITH'=> ESearchItemType::STARTS_WITH, "ESearchItemType::EXISTS"=> ESearchItemType::EXISTS, ESearchUnifiedItem::UNIFIED), @@ -42,6 +46,8 @@ class ESearchCuePointItem extends ESearchNestedObjectItem 'cue_points.cue_point_tags' => 50, 'cue_points.cue_point_question' => 50, 'cue_points.cue_point_answers' => 50, + 'cue_points.cue_point_hint' => 50, + 'cue_points.cue_point_explanation' => 50, ); private static $multiLanguageFields = array(); @@ -78,6 +84,22 @@ public function setSearchTerm($searchTerm) $this->searchTerm = $searchTerm; } + /** + * @return CuePointType + */ + public function getCuePointType() + { + return $this->cuePointType; + } + + /** + * @param CuePointType $cuePointType + */ + public function setCuePointType($cuePointType) + { + $this->cuePointType = $cuePointType; + } + public static function getAllowedSearchTypesForField() { return array_merge(self::$allowed_search_types_for_field, parent::getAllowedSearchTypesForField()); @@ -95,37 +117,32 @@ public static function createSearchQuery($eSearchItemsArr, $boolOperator, &$quer return self::createNestedQueryForItems($eSearchItemsArr, $boolOperator, $queryAttributes); } - public static function createSingleItemSearchQuery($cuePointSearchItem, $boolOperator, &$cuePointQuery, $allowedSearchTypes, &$queryAttributes) + public static function createSingleItemSearchQuery($cuePointSearchItem, $boolOperator, &$cuePointBoolQuery, $allowedSearchTypes, &$queryAttributes) { $cuePointSearchItem->validateItemInput(); + switch ($cuePointSearchItem->getItemType()) { case ESearchItemType::EXACT_MATCH: - $cuePointQuery['nested']['query']['bool'][$boolOperator][] = - kESearchQueryManager::getExactMatchQuery($cuePointSearchItem, $cuePointSearchItem->getFieldName(), $allowedSearchTypes, $queryAttributes); + $query = self::getCuePointExactMatchQuery($cuePointSearchItem, $allowedSearchTypes, $queryAttributes); break; case ESearchItemType::PARTIAL: - $cuePointQuery['nested']['query']['bool'][$boolOperator][] = - kESearchQueryManager::getMultiMatchQuery($cuePointSearchItem, $cuePointSearchItem->getFieldName(), $queryAttributes); + $query = self::getCuePointPartialQuery($cuePointSearchItem, $cuePointSearchItem->getFieldName(), $queryAttributes); break; case ESearchItemType::STARTS_WITH: - $cuePointQuery['nested']['query']['bool'][$boolOperator][] = - kESearchQueryManager::getPrefixQuery($cuePointSearchItem, $cuePointSearchItem->getFieldName(), $allowedSearchTypes, $queryAttributes); + $query = self::getCuePointPrefixQuery($cuePointSearchItem, $cuePointSearchItem->getFieldName(), $allowedSearchTypes, $queryAttributes); break; case ESearchItemType::EXISTS: - $cuePointQuery['nested']['query']['bool'][$boolOperator][] = - kESearchQueryManager::getExistsQuery($cuePointSearchItem, $cuePointSearchItem->getFieldName(), $allowedSearchTypes, $queryAttributes); + $query = self::getCuePointExistsQuery($cuePointSearchItem, $cuePointSearchItem->getFieldName(), $allowedSearchTypes, $queryAttributes); break; case ESearchItemType::RANGE: - $cuePointQuery['nested']['query']['bool'][$boolOperator][] = - kESearchQueryManager::getRangeQuery($cuePointSearchItem, $cuePointSearchItem->getFieldName(), $allowedSearchTypes, $queryAttributes); + $query = self::getCuePointRangeQuery($cuePointSearchItem, $cuePointSearchItem->getFieldName(), $allowedSearchTypes, $queryAttributes); break; default: KalturaLog::log("Undefined item type[".$cuePointSearchItem->getItemType()."]"); } - if($boolOperator == 'should') - $cuePointQuery['nested']['query']['bool']['minimum_should_match'] = 1; + $cuePointBoolQuery->addByOperatorType($boolOperator, $query); } public function shouldAddLanguageSearch() @@ -141,4 +158,80 @@ public function getItemMappingFieldsDelimiter() } + public function getNestedQueryName() + { + if($this->getCuePointType()) + { + $apiCuePointType = kPluginableEnumsManager::coreToApi('CuePointType', $this->getCuePointType()); + return ESearchItemDataType::CUE_POINTS.self::QUERY_NAME_DELIMITER.$apiCuePointType; + } + + return ESearchItemDataType::CUE_POINTS.self::QUERY_NAME_DELIMITER.self::DEFAULT_GROUP_NAME; + } + + protected static function getCuePointExactMatchQuery($cuePointSearchItem, $allowedSearchTypes, &$queryAttributes) + { + $cuePointExactMatch = kESearchQueryManager::getExactMatchQuery($cuePointSearchItem, $cuePointSearchItem->getFieldName(), $allowedSearchTypes, $queryAttributes); + if($cuePointSearchItem->getCuePointType()) + { + $cuePointExactMatch = self::addFilterByTypeToQuery($cuePointSearchItem->getCuePointType(), $cuePointExactMatch); + } + + return $cuePointExactMatch; + } + + protected static function getCuePointPartialQuery($cuePointSearchItem, $fieldName, &$queryAttributes) + { + $cuePointPartial = kESearchQueryManager::getPartialQuery($cuePointSearchItem, $fieldName, $queryAttributes); + if($cuePointSearchItem->getCuePointType()) + { + $cuePointTypeQuery = new kESearchTermQuery('cue_points.cue_point_type', $cuePointSearchItem->getCuePointType()); + $cuePointPartial->addToFilter($cuePointTypeQuery); + } + + return $cuePointPartial; + } + + protected static function getCuePointPrefixQuery($cuePointSearchItem, $fieldName, $allowedSearchTypes, &$queryAttributes) + { + $cuePointPrefix = kESearchQueryManager::getPrefixQuery($cuePointSearchItem, $fieldName, $allowedSearchTypes, $queryAttributes); + if($cuePointSearchItem->getCuePointType()) + { + $cuePointPrefix = self::addFilterByTypeToQuery($cuePointSearchItem->getCuePointType(), $cuePointPrefix); + } + + return $cuePointPrefix; + } + + protected static function getCuePointExistsQuery($cuePointSearchItem, $fieldName, $allowedSearchTypes, &$queryAttributes) + { + $cuePointExists = kESearchQueryManager::getExistsQuery($cuePointSearchItem, $fieldName, $allowedSearchTypes, $queryAttributes); + if($cuePointSearchItem->getCuePointType()) + { + $cuePointExists = self::addFilterByTypeToQuery($cuePointSearchItem->getCuePointType(), $cuePointExists); + } + + return $cuePointExists; + } + + protected static function getCuePointRangeQuery($cuePointSearchItem, $fieldName, $allowedSearchTypes, &$queryAttributes) + { + $cuePointRange = kESearchQueryManager::getRangeQuery($cuePointSearchItem, $fieldName, $allowedSearchTypes, $queryAttributes); + if($cuePointSearchItem->getCuePointType()) + { + $cuePointRange = self::addFilterByTypeToQuery($cuePointSearchItem->getCuePointType(), $cuePointRange); + } + + return $cuePointRange; + } + + private static function addFilterByTypeToQuery($cuePointType, &$query) + { + $cuePointTypeQuery = new kESearchTermQuery('cue_points.cue_point_type', $cuePointType); + $boolQuery = new kESearchBoolQuery(); + $boolQuery->addToFilter($cuePointTypeQuery); + $boolQuery->addToMust($query); + return $boolQuery; + } + } diff --git a/plugins/search/providers/elastic_search/lib/model/items/ESearchCuePointItemData.php b/plugins/search/providers/elastic_search/lib/model/items/ESearchCuePointItemData.php index a0d4bca27d6..ead6152a3d2 100644 --- a/plugins/search/providers/elastic_search/lib/model/items/ESearchCuePointItemData.php +++ b/plugins/search/providers/elastic_search/lib/model/items/ESearchCuePointItemData.php @@ -265,30 +265,46 @@ public function getType() public function loadFromElasticHits($objectResult) { - $this->cuePointType = $objectResult['_source']['cue_point_type']; + if(isset($objectResult['_source']['cue_point_type'])) + { + $apiCuePointType = kPluginableEnumsManager::coreToApi('CuePointType', $objectResult['_source']['cue_point_type']); + $this->cuePointType = $apiCuePointType; + } + $this->id = $objectResult['_source']['cue_point_id']; if (isset($objectResult['_source']['cue_point_name'])) $this->name = $objectResult['_source']['cue_point_name']; + if (isset($objectResult['_source']['cue_point_start_time'])) $this->startTime = $objectResult['_source']['cue_point_start_time']; + if (isset($objectResult['_source']['cue_point_end_time'])) $this->endTime = $objectResult['_source']['cue_point_end_time']; + if (isset($objectResult['_source']['cue_point_text'])) $this->text = $objectResult['_source']['cue_point_text']; + if (isset($objectResult['_source']['cue_point_tags'])) $this->tags = $objectResult['_source']['cue_point_tags']; + if (isset($objectResult['_source']['cue_point_sub_type'])) $this->subType = $objectResult['_source']['cue_point_sub_type']; + if (isset($objectResult['_source']['cue_point_question'])) $this->question = $objectResult['_source']['cue_point_question']; + if (isset($objectResult['_source']['cue_point_answers'])) $this->answers = $objectResult['_source']['cue_point_answers']; + if (isset($objectResult['_source']['cue_point_hint'])) $this->hint = $objectResult['_source']['cue_point_hint']; + if (isset($objectResult['_source']['cue_point_explanation'])) $this->explanation = $objectResult['_source']['cue_point_explanation']; - $this->setHighlight($objectResult['highlight']); + if(isset($objectResult['highlight'])) + $this->setHighlight($objectResult['highlight']); + } } \ No newline at end of file diff --git a/plugins/search/providers/elastic_search/lib/model/items/ESearchEntryItem.php b/plugins/search/providers/elastic_search/lib/model/items/ESearchEntryItem.php index 422a364d00a..22fac3215fb 100644 --- a/plugins/search/providers/elastic_search/lib/model/items/ESearchEntryItem.php +++ b/plugins/search/providers/elastic_search/lib/model/items/ESearchEntryItem.php @@ -68,6 +68,11 @@ class ESearchEntryItem extends ESearchItem ESearchEntryFieldName::ENTRY_DESCRIPTION, ); + private static $ignoreDisplayInSearchFields = array( + ESearchEntryFieldName::ENTRY_PARENT_ENTRY_ID, + ESearchEntryFieldName::ENTRY_ID, + ); + /** * @return ESearchEntryFieldName */ @@ -134,7 +139,7 @@ public static function getSingleItemSearchQuery($entrySearchItem, &$entryQuery, $entryQuery[] = kESearchQueryManager::getExactMatchQuery($entrySearchItem, $entrySearchItem->getFieldName(), $allowedSearchTypes, $queryAttributes); break; case ESearchItemType::PARTIAL: - $entryQuery[] = kESearchQueryManager::getMultiMatchQuery($entrySearchItem, $entrySearchItem->getFieldName(), $queryAttributes); + $entryQuery[] = kESearchQueryManager::getPartialQuery($entrySearchItem, $entrySearchItem->getFieldName(), $queryAttributes); break; case ESearchItemType::STARTS_WITH: $entryQuery[] = kESearchQueryManager::getPrefixQuery($entrySearchItem, $entrySearchItem->getFieldName(), $allowedSearchTypes, $queryAttributes); @@ -148,6 +153,8 @@ public static function getSingleItemSearchQuery($entrySearchItem, &$entryQuery, default: KalturaLog::log("Undefined item type[".$entrySearchItem->getItemType()."]"); } + if (in_array($entrySearchItem->getFieldName(), self::$ignoreDisplayInSearchFields)) + $queryAttributes->setShouldUseDisplayInSearch(false); } public function shouldAddLanguageSearch() diff --git a/plugins/search/providers/elastic_search/lib/model/items/ESearchItemData.php b/plugins/search/providers/elastic_search/lib/model/items/ESearchItemData.php index 30da21a43b9..00bf86dad23 100644 --- a/plugins/search/providers/elastic_search/lib/model/items/ESearchItemData.php +++ b/plugins/search/providers/elastic_search/lib/model/items/ESearchItemData.php @@ -10,12 +10,12 @@ abstract public function getType(); abstract public function loadFromElasticHits($objectResult); /** - * @var string + * @var array */ protected $highlight; /** - * @return string + * @return array */ public function getHighlight() { diff --git a/plugins/search/providers/elastic_search/lib/model/items/ESearchMetadataItem.php b/plugins/search/providers/elastic_search/lib/model/items/ESearchMetadataItem.php index c39576a72d7..826a395f234 100644 --- a/plugins/search/providers/elastic_search/lib/model/items/ESearchMetadataItem.php +++ b/plugins/search/providers/elastic_search/lib/model/items/ESearchMetadataItem.php @@ -15,6 +15,11 @@ class ESearchMetadataItem extends ESearchNestedObjectItem 'metadata.value_int' => array('ESearchItemType::EXACT_MATCH'=> ESearchItemType::EXACT_MATCH, "ESearchItemType::EXISTS"=> ESearchItemType::EXISTS, 'ESearchItemType::RANGE'=>ESearchItemType::RANGE, ESearchUnifiedItem::UNIFIED), ); + protected static $field_boost_values = array( + 'metadata.value_text' => 100, + 'metadata.value_int' => 100, + ); + /** * @var string */ @@ -117,38 +122,31 @@ public static function createSearchQuery($eSearchItemsArr, $boolOperator, &$quer return self::createNestedQueryForItems($eSearchItemsArr, $boolOperator, $queryAttributes); } - public static function createSingleItemSearchQuery($metadataESearchItem, $boolOperator, &$metadataQuery, $allowedSearchTypes, &$queryAttributes) + public static function createSingleItemSearchQuery($metadataESearchItem, $boolOperator, &$metadataBoolQuery, $allowedSearchTypes, &$queryAttributes) { $metadataESearchItem->validateItemInput(); switch ($metadataESearchItem->getItemType()) { case ESearchItemType::EXACT_MATCH: - $metadataQuery['nested']['query']['bool'][$boolOperator][] = - self::getMetadataExactMatchQuery($metadataESearchItem, $allowedSearchTypes, $queryAttributes); + $query = self::getMetadataExactMatchQuery($metadataESearchItem, $allowedSearchTypes, $queryAttributes); break; case ESearchItemType::PARTIAL: - $metadataQuery['nested']['query']['bool'][$boolOperator][] = - self::getMetadataMultiMatchQuery($metadataESearchItem, $queryAttributes); + $query = self::getMetadataPartialQuery($metadataESearchItem, $queryAttributes); break; case ESearchItemType::STARTS_WITH: - $metadataQuery['nested']['query']['bool'][$boolOperator][] = - self::getMetadataPrefixQuery($metadataESearchItem, $allowedSearchTypes, $queryAttributes); + $query = self::getMetadataPrefixQuery($metadataESearchItem, $allowedSearchTypes, $queryAttributes); break; case ESearchItemType::EXISTS: - $metadataQuery['nested']['query']['bool'][$boolOperator][] = - self::getMetadataExistQuery($metadataESearchItem, $allowedSearchTypes, $queryAttributes); + $query = self::getMetadataExistQuery($metadataESearchItem, $allowedSearchTypes, $queryAttributes); break; case ESearchItemType::RANGE: - $metadataQuery['nested']['query']['bool'][$boolOperator][] = - self::getMetadataRangeQuery($metadataESearchItem, $allowedSearchTypes, $queryAttributes); + $query = self::getMetadataRangeQuery($metadataESearchItem, $allowedSearchTypes, $queryAttributes); break; default: KalturaLog::log("Undefined item type[".$metadataESearchItem->getItemType()."]"); } - if($boolOperator == 'should') - $metadataQuery['nested']['query']['bool']['minimum_should_match'] = 1; - + $metadataBoolQuery->addByOperatorType($boolOperator, $query); } /** @@ -159,30 +157,33 @@ public static function createSingleItemSearchQuery($metadataESearchItem, $boolOp */ protected static function getMetadataExactMatchQuery($searchItem, $allowedSearchTypes, &$queryAttributes) { - $metadataExactMatch = array(); if(ctype_digit($searchItem->getSearchTerm())) { - $metadataExactMatch['bool']['should'][] = kESearchQueryManager::getExactMatchQuery($searchItem, 'metadata.value_text', $allowedSearchTypes, $queryAttributes); - $metadataExactMatch['bool']['should'][] = kESearchQueryManager::getExactMatchQuery($searchItem, 'metadata.value_int', $allowedSearchTypes, $queryAttributes); - $metadataExactMatch['bool']['minimum_should_match'] = 1; + $metadataExactMatch = new kESearchBoolQuery(); + $textExactMatch = kESearchQueryManager::getExactMatchQuery($searchItem, 'metadata.value_text', $allowedSearchTypes, $queryAttributes); + $metadataExactMatch->addToShould($textExactMatch); + $intExactMatch = kESearchQueryManager::getExactMatchQuery($searchItem, 'metadata.value_int', $allowedSearchTypes, $queryAttributes); + $metadataExactMatch->addToShould($intExactMatch); } else if($searchItem->getXpath() || $searchItem->getMetadataProfileId() || $searchItem->getMetadataFieldId()) { - $metadataExactMatch['bool']['must'][] = kESearchQueryManager::getExactMatchQuery($searchItem, 'metadata.value_text', $allowedSearchTypes, $queryAttributes); + $metadataExactMatch = new kESearchBoolQuery(); + $textExactMatch = kESearchQueryManager::getExactMatchQuery($searchItem, 'metadata.value_text', $allowedSearchTypes, $queryAttributes); + $metadataExactMatch->addToMust($textExactMatch); } else { - $metadataExactMatch = kESearchQueryManager::getExactMatchQuery($searchItem, 'metadata.value_text', $allowedSearchTypes, $queryAttributes); + return kESearchQueryManager::getExactMatchQuery($searchItem, 'metadata.value_text', $allowedSearchTypes, $queryAttributes); } if($searchItem->getXpath()) - $metadataExactMatch['bool']['must'][] = self::getXPathQuery($searchItem); + $metadataExactMatch->addToFilter(self::getXPathQuery($searchItem)); if($searchItem->getMetadataProfileId()) - $metadataExactMatch['bool']['must'][] = self::getMetadataProfileIdQuery($searchItem); + $metadataExactMatch->addToFilter(self::getMetadataProfileIdQuery($searchItem)); if($searchItem->getMetadataFieldId()) - $metadataExactMatch['bool']['must'][] = self::getMetadataFieldIdQuery($searchItem); + $metadataExactMatch->addToFilter(self::getMetadataFieldIdQuery($searchItem)); return $metadataExactMatch; } @@ -192,31 +193,33 @@ protected static function getMetadataExactMatchQuery($searchItem, $allowedSearch * @param ESearchQueryAttributes $queryAttributes * @return array|null */ - protected static function getMetadataMultiMatchQuery($searchItem, &$queryAttributes) + protected static function getMetadataPartialQuery($searchItem, &$queryAttributes) { - $metadataMultiMatch = kESearchQueryManager::getMultiMatchQuery($searchItem, 'metadata.value_text', $queryAttributes); - + /**@var kESearchBoolQuery $metadataMultiMatch*/ + $metadataPartialQuery = kESearchQueryManager::getPartialQuery($searchItem, 'metadata.value_text', $queryAttributes); if(ctype_digit($searchItem->getSearchTerm()))//add metadata.value_int - $metadataMultiMatch['bool']['should'][0]['multi_match']['fields'][] = 'metadata.value_int^3'; - - if($searchItem->getXpath() || $searchItem->getMetadataProfileId() || $searchItem->getMetadataFieldId()) { - $metadataMultiMatchQuery = $metadataMultiMatch; - $metadataMultiMatch = null; - - $metadataMultiMatch['bool']['must'][] = $metadataMultiMatchQuery; + $partialShouldQueries = $metadataPartialQuery->getShouldQueries(); + foreach($partialShouldQueries as $partialShouldQuery) + { + if($partialShouldQuery instanceof kESearchMultiMatchQuery) + { + $partialShouldQuery->addToFields('metadata.value_int^'.kESearchQueryManager::RAW_FIELD_BOOST_FACTOR); + break; + } + } + } - if($searchItem->getXpath()) - $metadataMultiMatch['bool']['must'][] = self::getXPathQuery($searchItem); + if($searchItem->getXpath()) + $metadataPartialQuery->addToFilter(self::getXPathQuery($searchItem)); - if($searchItem->getMetadataProfileId()) - $metadataMultiMatch['bool']['must'][] = self::getMetadataProfileIdQuery($searchItem); + if($searchItem->getMetadataProfileId()) + $metadataPartialQuery->addToFilter(self::getMetadataProfileIdQuery($searchItem)); - if($searchItem->getMetadataFieldId()) - $metadataMultiMatch['bool']['must'][] = self::getMetadataFieldIdQuery($searchItem); - } + if($searchItem->getMetadataFieldId()) + $metadataPartialQuery->addToFilter(self::getMetadataFieldIdQuery($searchItem)); - return $metadataMultiMatch; + return $metadataPartialQuery; } /** @@ -231,19 +234,19 @@ protected static function getMetadataPrefixQuery($searchItem, $allowedSearchType if($searchItem->getXpath() || $searchItem->getMetadataProfileId() || $searchItem->getMetadataFieldId()) { - $metaDataPrefixQuery = $metaDataPrefix; - $metaDataPrefix = null; - - $metaDataPrefix['bool']['must'][] = $metaDataPrefixQuery; + $metaDataPrefixQuery = new kESearchBoolQuery(); + $metaDataPrefixQuery->addToMust($metaDataPrefix); if($searchItem->getXpath()) - $metaDataPrefix['bool']['must'][] = self::getXPathQuery($searchItem); + $metaDataPrefixQuery->addToFilter(self::getXPathQuery($searchItem)); if($searchItem->getMetadataProfileId()) - $metaDataPrefix['bool']['must'][] = self::getMetadataProfileIdQuery($searchItem); + $metaDataPrefixQuery->addToFilter(self::getMetadataProfileIdQuery($searchItem)); if($searchItem->getMetadataFieldId()) - $metaDataPrefix['bool']['must'][] = self::getMetadataFieldIdQuery($searchItem); + $metaDataPrefixQuery->addToFilter(self::getMetadataFieldIdQuery($searchItem)); + + $metaDataPrefix = $metaDataPrefixQuery; } return $metaDataPrefix; @@ -257,20 +260,20 @@ protected static function getMetadataPrefixQuery($searchItem, $allowedSearchType */ protected static function getMetadataExistQuery($searchItem, $allowedSearchTypes, &$queryAttributes) { - $metadataExist = array(); - - $metadataExist['bool']['should'][] = kESearchQueryManager::getExistsQuery(null, 'metadata.value_text', $allowedSearchTypes, $queryAttributes); - $metadataExist['bool']['should'][] = kESearchQueryManager::getExistsQuery(null, 'metadata.value_int', $allowedSearchTypes, $queryAttributes); - $metadataExist['bool']['minimum_should_match'] = 1; + $metadataExist = new kESearchBoolQuery(); + $metadataTextExist = kESearchQueryManager::getExistsQuery(null, 'metadata.value_text', $allowedSearchTypes, $queryAttributes); + $metadataExist->addToShould($metadataTextExist); + $metadataIntExist = kESearchQueryManager::getExistsQuery(null, 'metadata.value_int', $allowedSearchTypes, $queryAttributes); + $metadataExist->addToShould($metadataIntExist); if($searchItem->getXpath()) - $metadataExist['bool']['must'][] = self::getXPathQuery($searchItem); + $metadataExist->addToFilter(self::getXPathQuery($searchItem)); if($searchItem->getMetadataProfileId()) - $metadataExist['bool']['must'][] = self::getMetadataProfileIdQuery($searchItem); + $metadataExist->addToFilter(self::getMetadataProfileIdQuery($searchItem)); if($searchItem->getMetadataFieldId()) - $metadataExist['bool']['must'][] = self::getMetadataFieldIdQuery($searchItem); + $metadataExist->addToFilter(self::getMetadataFieldIdQuery($searchItem)); return $metadataExist; } @@ -286,19 +289,19 @@ protected static function getMetadataRangeQuery($searchItem, $allowedSearchTypes if($searchItem->getXpath() || $searchItem->getMetadataProfileId() || $searchItem->getMetadataFieldId()) { - $metadataRangeQuery = $metadataRange; - $metadataRange = null; - - $metadataRange['bool']['must'][] = $metadataRangeQuery; + $metadataRangeQuery = new kESearchBoolQuery(); + $metadataRangeQuery->addToMust($metadataRange); if($searchItem->getXpath()) - $metadataRange['bool']['must'][] = self::getXPathQuery($searchItem); + $metadataRangeQuery->addToFilter(self::getXPathQuery($searchItem)); if($searchItem->getMetadataProfileId()) - $metadataRange['bool']['must'][] = self::getMetadataProfileIdQuery($searchItem); + $metadataRangeQuery->addToFilter(self::getMetadataProfileIdQuery($searchItem)); if($searchItem->getMetadataFieldId()) - $metadataRange['bool']['must'][] = self::getMetadataFieldIdQuery($searchItem); + $metadataRangeQuery->addToFilter(self::getMetadataFieldIdQuery($searchItem)); + + $metadataRange = $metadataRangeQuery; } return $metadataRange; @@ -306,33 +309,24 @@ protected static function getMetadataRangeQuery($searchItem, $allowedSearchTypes protected static function getXPathQuery($metadataESearchItem) { - $xpathQuery = array( - 'term' => array( - 'metadata.xpath' => elasticSearchUtils::formatSearchTerm($metadataESearchItem->getXpath()) - ) - ); + $xpath = elasticSearchUtils::formatSearchTerm($metadataESearchItem->getXpath()); + $xpathQuery = new kESearchTermQuery('metadata.xpath', $xpath); return $xpathQuery; } protected static function getMetadataProfileIdQuery($metadataESearchItem) { - $metadataProfileIdQuery = array( - 'term' => array( - 'metadata.metadata_profile_id' => elasticSearchUtils::formatSearchTerm($metadataESearchItem->getMetadataProfileId()) - ) - ); + $profileId = elasticSearchUtils::formatSearchTerm($metadataESearchItem->getMetadataProfileId()); + $metadataProfileIdQuery = new kESearchTermQuery('metadata.metadata_profile_id', $profileId); return $metadataProfileIdQuery; } protected static function getMetadataFieldIdQuery($metadataESearchItem) { - $metadataFieldIdQuery = array( - 'term' => array( - 'metadata.metadata_field_id' => elasticSearchUtils::formatSearchTerm($metadataESearchItem->getMetadataFieldId()) - ) - ); + $fieldId = elasticSearchUtils::formatSearchTerm($metadataESearchItem->getMetadataFieldId()); + $metadataFieldIdQuery = new kESearchTermQuery('metadata.metadata_field_id', $fieldId); return $metadataFieldIdQuery; } @@ -364,4 +358,9 @@ public function getItemMappingFieldsDelimiter() } + public function getNestedQueryName() + { + return ESearchItemDataType::METADATA.self::QUERY_NAME_DELIMITER.self::DEFAULT_GROUP_NAME; + } + } \ No newline at end of file diff --git a/plugins/search/providers/elastic_search/lib/model/items/ESearchMetadataItemData.php b/plugins/search/providers/elastic_search/lib/model/items/ESearchMetadataItemData.php index 41593659197..61d3624038c 100644 --- a/plugins/search/providers/elastic_search/lib/model/items/ESearchMetadataItemData.php +++ b/plugins/search/providers/elastic_search/lib/model/items/ESearchMetadataItemData.php @@ -127,7 +127,8 @@ public function loadFromElasticHits($objectResult) if(isset($objectResult['_source']['value_int'])) $this->setValueInt($objectResult['_source']['value_int']); - $this->setHighlight($objectResult['highlight']); + if(isset($objectResult['highlight'])) + $this->setHighlight($objectResult['highlight']); } } \ No newline at end of file diff --git a/plugins/search/providers/elastic_search/lib/model/items/ESearchNestedObjectItem.php b/plugins/search/providers/elastic_search/lib/model/items/ESearchNestedObjectItem.php index 2af97c71a27..f4a6e18f6fc 100644 --- a/plugins/search/providers/elastic_search/lib/model/items/ESearchNestedObjectItem.php +++ b/plugins/search/providers/elastic_search/lib/model/items/ESearchNestedObjectItem.php @@ -7,6 +7,8 @@ abstract class ESearchNestedObjectItem extends ESearchItem { const DEFAULT_INNER_HITS_SIZE = 10; + const DEFAULT_GROUP_NAME = 'default_group'; + const QUERY_NAME_DELIMITER = '#DEL#'; protected static function initializeInnerHitsSize($queryAttributes) { @@ -23,45 +25,96 @@ protected static function initializeInnerHitsSize($queryAttributes) protected static function createNestedQueryForItems($eSearchItemsArr, $boolOperator, &$queryAttributes) { - $finalQuery = array(); $innerHitsSize = self::initializeInnerHitsSize($queryAttributes); $allowedSearchTypes = static::getAllowedSearchTypesForField(); // must_not was already set in a higher level of the query inside ESearchOperator if($boolOperator == 'must_not') $boolOperator = 'must'; - + //don't group to a single query if the operator is AND if($boolOperator == 'must') - { - foreach ($eSearchItemsArr as $eSearchItem) - { - $nestedQuery = null; - $nestedQuery['nested']['path'] = static::NESTED_QUERY_PATH; - $nestedQuery['nested']['inner_hits'] = array('size' => $innerHitsSize, '_source' => true); - $queryAttributes->setScopeToInner(); - static::createSingleItemSearchQuery($eSearchItem, $boolOperator, $nestedQuery, $allowedSearchTypes, $queryAttributes); - $highlight = kBaseSearch::getHighlightSection(static::HIGHLIGHT_CONFIG_KEY, $queryAttributes); - if(isset($highlight)) - $nestedQuery['nested']['inner_hits']['highlight'] = $highlight; - $finalQuery[] = $nestedQuery; - } - } + $finalQuery = static::createNestedQueries($eSearchItemsArr, $innerHitsSize,$queryAttributes,$boolOperator,$allowedSearchTypes); else + $finalQuery = static::createGroupedNestedQueries($eSearchItemsArr, $innerHitsSize, $queryAttributes, $boolOperator, $allowedSearchTypes); + + return $finalQuery; + } + + protected static function createNestedQueries($eSearchItemsArr, $innerHitsSize, &$queryAttributes, $boolOperator, $allowedSearchTypes) + { + $finalQuery = array(); + foreach ($eSearchItemsArr as $eSearchItem) { - $nestedQuery['nested']['path'] = static::NESTED_QUERY_PATH;; - $nestedQuery['nested']['inner_hits'] = array('size' => $innerHitsSize, '_source' => true); + $nestedQuery = new kESearchNestedQuery(); + $nestedQuery->setPath(static::NESTED_QUERY_PATH); + $nestedQuery->setInnerHitsSize($innerHitsSize); + $nestedQuery->setInnerHitsSource(true); + if($eSearchItem->getNestedQueryName()) + $nestedQuery->setInnerHitsName($eSearchItem->getNestedQueryName()); $queryAttributes->setScopeToInner(); - foreach ($eSearchItemsArr as $eSearchItem) - { - static::createSingleItemSearchQuery($eSearchItem, $boolOperator, $nestedQuery, $allowedSearchTypes, $queryAttributes); - } + $boolQuery = new kESearchBoolQuery(); + static::createSingleItemSearchQuery($eSearchItem, $boolOperator, $boolQuery, $allowedSearchTypes, $queryAttributes); $highlight = kBaseSearch::getHighlightSection(static::HIGHLIGHT_CONFIG_KEY, $queryAttributes); if(isset($highlight)) - $nestedQuery['nested']['inner_hits']['highlight'] = $highlight; + $nestedQuery->setHighlight($highlight); + $nestedQuery->setQuery($boolQuery); $finalQuery[] = $nestedQuery; } return $finalQuery; } + protected static function createGroupedNestedQueries($eSearchItemsArr, $innerHitsSize, &$queryAttributes, $boolOperator, $allowedSearchTypes, $name = null) + { + $finalQuery = array(); + $groupedItems = self::groupItemsByQueryName($eSearchItemsArr); + + foreach ($groupedItems as $name => $items) + { + $nestedQuery = self::createGroupedNestedQuery($items, $innerHitsSize, $queryAttributes, $boolOperator, $allowedSearchTypes, $name); + $finalQuery[] = $nestedQuery[0]; + } + return $finalQuery; + } + + protected static function createGroupedNestedQuery($eSearchItemsArr, $innerHitsSize, &$queryAttributes, $boolOperator, $allowedSearchTypes, $groupQueryName = null) + { + $finalQuery = array(); + $nestedQuery = new kESearchNestedQuery(); + $nestedQuery->setPath(static::NESTED_QUERY_PATH); + $nestedQuery->setInnerHitsSize($innerHitsSize); + $nestedQuery->setInnerHitsSource(true); + if($groupQueryName) + $nestedQuery->setInnerHitsName($groupQueryName); + $queryAttributes->setScopeToInner(); + $boolQuery = new kESearchBoolQuery(); + foreach ($eSearchItemsArr as $eSearchItem) + { + static::createSingleItemSearchQuery($eSearchItem, $boolOperator, $boolQuery, $allowedSearchTypes, $queryAttributes); + } + $highlight = kBaseSearch::getHighlightSection(static::HIGHLIGHT_CONFIG_KEY, $queryAttributes); + if(isset($highlight)) + $nestedQuery->setHighlight($highlight); + $nestedQuery->setQuery($boolQuery); + $finalQuery[] = $nestedQuery; + + return $finalQuery; + } + + abstract public function getNestedQueryName(); + + protected static function groupItemsByQueryName($eSearchItemsArr) + { + $groupedItems = array(); + foreach ($eSearchItemsArr as $item) + { + $nestedQueryName = $item->getNestedQueryName(); + if($nestedQueryName) + $groupedItems[$nestedQueryName][] = $item; + else + $groupedItems[self::DEFAULT_GROUP_NAME][] = $item; + } + return $groupedItems; + } + } diff --git a/plugins/search/providers/elastic_search/lib/model/items/ESearchOperator.php b/plugins/search/providers/elastic_search/lib/model/items/ESearchOperator.php index cac37b149e7..bd8fe4e3a56 100644 --- a/plugins/search/providers/elastic_search/lib/model/items/ESearchOperator.php +++ b/plugins/search/providers/elastic_search/lib/model/items/ESearchOperator.php @@ -57,13 +57,13 @@ public static function createSearchQuery($eSearchItemsArr, $boolOperator, &$quer switch ($eSearchOperatorType) { case ESearchOperatorType::AND_OP: - $boolOperator = 'must'; + $boolOperator = kESearchBoolQuery::MUST_KEY; break; case ESearchOperatorType::OR_OP: - $boolOperator = 'should'; + $boolOperator = kESearchBoolQuery::SHOULD_KEY; break; case ESearchOperatorType::NOT_OP: - $boolOperator = 'must_not'; + $boolOperator = kESearchBoolQuery::MUST_NOT_KEY; break; default: KalturaLog::crit('unknown operator type'); @@ -109,7 +109,7 @@ private static function getCategorizedSearchItems($eSearchCaptionItemsArr) private static function createSearchQueryForItems($categorizedSearchItems, $boolOperator, &$queryAttributes, $eSearchOperatorType) { - $outQuery = array(); + $outQuery = new kESearchBoolQuery(); foreach ($categorizedSearchItems as $categorizedSearchItem) { $itemClassName = $categorizedSearchItem['className']; @@ -120,21 +120,21 @@ private static function createSearchQueryForItems($categorizedSearchItems, $bool $itemSearchItems = $itemSearchItems->getSearchItems(); $operatorType = $categorizedSearchItem['operatorType']; } - + $subQuery = call_user_func(array($itemClassName, 'createSearchQuery'), $itemSearchItems, $boolOperator, $queryAttributes, $operatorType); - foreach ($subQuery as $key => $value) + if($itemClassName == get_class()) + $outQuery->addByOperatorType($boolOperator, $subQuery); + else { - if($itemClassName == get_class()) - $outQuery['bool'][$boolOperator][] = $subQuery; - else - $outQuery['bool'][$boolOperator][] = $value; + foreach ($subQuery as $key => $value) + { + $outQuery->addByOperatorType($boolOperator, $value); + } } + } - if($eSearchOperatorType == ESearchOperatorType::OR_OP && count($outQuery['bool'][$boolOperator])) - $outQuery['bool']['minimum_should_match'] = 1; - return $outQuery; } diff --git a/plugins/search/providers/elastic_search/lib/model/items/ESearchUnifiedItem.php b/plugins/search/providers/elastic_search/lib/model/items/ESearchUnifiedItem.php index a02827015f7..fefc2ce1308 100644 --- a/plugins/search/providers/elastic_search/lib/model/items/ESearchUnifiedItem.php +++ b/plugins/search/providers/elastic_search/lib/model/items/ESearchUnifiedItem.php @@ -36,20 +36,14 @@ public static function createSearchQuery($eSearchItemsArr, $boolOperator, &$quer foreach($eSearchItemsArr as $eSearchUnifiedItem) { self::validateUnifiedAllowedTypes($eSearchUnifiedItem); - $subQuery = array(); - $entryUnifiedQuery = array(); - self::addEntryFieldsToUnifiedQuery($eSearchUnifiedItem, $entryUnifiedQuery, $queryAttributes); - self::addCuePointFieldsToUnifiedQuery($eSearchUnifiedItem,$entryUnifiedQuery, $queryAttributes); - self::addCaptionFieldsToUnifiedQuery($eSearchUnifiedItem,$entryUnifiedQuery, $queryAttributes); - self::addMetadataFieldsToUnifiedQuery($eSearchUnifiedItem,$entryUnifiedQuery, $queryAttributes); - - if(count($entryUnifiedQuery)) - { - $subQuery['bool']['should'] = $entryUnifiedQuery; - $subQuery['bool']['minimum_should_match'] = 1; - $outQuery[] = $subQuery; - } - + $subQuery = new kESearchBoolQuery(); + + self::addEntryFieldsToUnifiedQuery($eSearchUnifiedItem, $subQuery, $queryAttributes); + self::addCuePointFieldsToUnifiedQuery($eSearchUnifiedItem, $subQuery, $queryAttributes); + self::addCaptionFieldsToUnifiedQuery($eSearchUnifiedItem, $subQuery, $queryAttributes); + self::addMetadataFieldsToUnifiedQuery($eSearchUnifiedItem, $subQuery, $queryAttributes); + + $outQuery[] = $subQuery; } return $outQuery; @@ -76,8 +70,13 @@ private static function addEntryFieldsToUnifiedQuery($eSearchUnifiedItem, &$entr if(count($entryItems)) { - $entryUnifiedQuery = ESearchEntryItem::createSearchQuery($entryItems, 'should', $queryAttributes, null); + $entryQueries = ESearchEntryItem::createSearchQuery($entryItems, 'should', $queryAttributes, null); + foreach ($entryQueries as $entryQuery) + { + $entryUnifiedQuery->addToShould($entryQuery); + } } + } private static function addCuePointFieldsToUnifiedQuery($eSearchUnifiedItem, &$entryUnifiedQuery, &$queryAttributes) @@ -101,9 +100,11 @@ private static function addCuePointFieldsToUnifiedQuery($eSearchUnifiedItem, &$e if(count($cuePointItems)) { - $cuePointQuery = ESearchCuePointItem::createSearchQuery($cuePointItems, 'should', $queryAttributes, null); - if(count($cuePointQuery)) - $entryUnifiedQuery[] = $cuePointQuery; + $cuePointQueries = ESearchCuePointItem::createSearchQuery($cuePointItems, 'should', $queryAttributes, null); + foreach ($cuePointQueries as $cuePointQuery) + { + $entryUnifiedQuery->addToShould($cuePointQuery); + } } } @@ -127,10 +128,13 @@ private static function addCaptionFieldsToUnifiedQuery($eSearchUnifiedItem, &$en if(count($captionItems)) { - $captionQuery = ESearchCaptionItem::createSearchQuery($captionItems, 'should', $queryAttributes, null); - if(count($captionQuery)) - $entryUnifiedQuery[] = $captionQuery; + $captionQueries = ESearchCaptionItem::createSearchQuery($captionItems, 'should', $queryAttributes, null); + foreach ($captionQueries as $captionQuery) + { + $entryUnifiedQuery->addToShould($captionQuery); + } } + } private static function addMetadataFieldsToUnifiedQuery($eSearchUnifiedItem, &$entryUnifiedQuery, &$queryAttributes) @@ -144,9 +148,14 @@ private static function addMetadataFieldsToUnifiedQuery($eSearchUnifiedItem, &$e $metadataItem->setRange($eSearchUnifiedItem->getRange()); $metadataItems[] = $metadataItem; - $metadataQuery = ESearchMetadataItem::createSearchQuery($metadataItems, 'should', $queryAttributes, null); - if(count($metadataQuery)) - $entryUnifiedQuery[] = $metadataQuery; + if(count($metadataItems)) + { + $metadataQueries = ESearchMetadataItem::createSearchQuery($metadataItems, 'should', $queryAttributes, null); + foreach ($metadataQueries as $metadataQuery) + { + $entryUnifiedQuery->addToShould($metadataQuery); + } + } } protected static function validateUnifiedAllowedTypes($eSearchUnifiedItem) diff --git a/plugins/search/providers/elastic_search/lib/model/items/ESearchUserItem.php b/plugins/search/providers/elastic_search/lib/model/items/ESearchUserItem.php index 07e0886a320..0b13fd63e5f 100644 --- a/plugins/search/providers/elastic_search/lib/model/items/ESearchUserItem.php +++ b/plugins/search/providers/elastic_search/lib/model/items/ESearchUserItem.php @@ -98,7 +98,7 @@ private static function getSingleItemSearchQuery($userSearchItem, &$userQuery, $ $userQuery[] = kESearchQueryManager::getExactMatchQuery($userSearchItem, $userSearchItem->getFieldName(), $allowedSearchTypes, $queryAttributes); break; case ESearchItemType::PARTIAL: - $userQuery[] = kESearchQueryManager::getMultiMatchQuery($userSearchItem, $userSearchItem->getFieldName(), $queryAttributes); + $userQuery[] = kESearchQueryManager::getPartialQuery($userSearchItem, $userSearchItem->getFieldName(), $queryAttributes); break; case ESearchItemType::STARTS_WITH: $userQuery[] = kESearchQueryManager::getPrefixQuery($userSearchItem, $userSearchItem->getFieldName(), $allowedSearchTypes, $queryAttributes); diff --git a/plugins/search/providers/elastic_search/lib/model/kESearchCoreAdapter.php b/plugins/search/providers/elastic_search/lib/model/kESearchCoreAdapter.php index 8ec997e3641..00196fbf52d 100644 --- a/plugins/search/providers/elastic_search/lib/model/kESearchCoreAdapter.php +++ b/plugins/search/providers/elastic_search/lib/model/kESearchCoreAdapter.php @@ -22,15 +22,15 @@ class kESearchCoreAdapter const HIGHLIGHT_KEY = 'highlight'; private static $innerHitsObjectType = array( - 'caption_assets.lines' => ESearchItemDataType::CAPTION, + 'caption' => ESearchItemDataType::CAPTION, 'metadata' => ESearchItemDataType::METADATA, 'cue_points' => ESearchItemDataType::CUE_POINTS ); - public static function transformElasticToCoreObject($elasticResults, $peerName) + public static function transformElasticToCoreObject($elasticResults, $peerName, $peerRetrieveFunctionName) { list($objectData, $objectOrder, $objectCount, $objectHighlight) = self::getElasticResultAsArray($elasticResults); - $objects = $peerName::retrieveByPKsNoFilter(array_keys($objectData)); + $objects = $peerName::$peerRetrieveFunctionName(array_keys($objectData)); $coreResults = self::getCoreESearchResults($objects, $objectData, $objectOrder, $objectHighlight); return array($coreResults, $objectCount); } @@ -50,7 +50,7 @@ private static function getElasticResultAsArray($elasticResults) $objectData[$elasticObject[self::ID_KEY]] = $itemData; $objectOrder[$elasticObject[self::ID_KEY]] = $key; if(array_key_exists(self::HIGHLIGHT_KEY, $elasticObject)) - $objectHighlight[$elasticObject[self::ID_KEY]] = self::pruneHighlight($elasticObject[self::HIGHLIGHT_KEY]); + $objectHighlight[$elasticObject[self::ID_KEY]] = self::elasticHighlightToCoreHighlight($elasticObject[self::HIGHLIGHT_KEY]); } if(isset($elasticResults[self::HITS_KEY][self::TOTAL_KEY])) @@ -89,19 +89,23 @@ private static function getItemDataFromInnerHits($elasticObject, &$itemData) { foreach ($elasticObject[self::INNER_HITS_KEY] as $innerHitsKey => $hits) { - $objectType = self::getInnerHitsObjectType($innerHitsKey); - $itemData[$objectType] = array(); - $itemData[$objectType][self::TOTAL_COUNT_KEY] = self::getInnerHitsTotalCountForObject($hits, $objectType); + list($objectType, $objectSubType) = self::getInnerHitsObjectType($innerHitsKey); + $itemsType = $objectType; + if($objectSubType) + $itemsType = "$itemsType::$objectSubType"; + + $itemData[$itemsType] = array(); + $itemData[$itemsType][self::TOTAL_COUNT_KEY] = self::getInnerHitsTotalCountForObject($hits, $objectType); foreach ($hits[self::HITS_KEY][self::HITS_KEY] as $itemResult) { $currItemData = KalturaPluginManager::loadObject('ESearchItemData', $objectType); if ($currItemData) { if(array_key_exists(self::HIGHLIGHT_KEY, $itemResult)) - $itemResult[self::HIGHLIGHT_KEY] = self::pruneHighlight($itemResult[self::HIGHLIGHT_KEY]); + $itemResult[self::HIGHLIGHT_KEY] = self::elasticHighlightToCoreHighlight($itemResult[self::HIGHLIGHT_KEY]); $currItemData->loadFromElasticHits($itemResult); - $itemData[$objectType][self::ITEMS_KEY][] = $currItemData; + $itemData[$itemsType][self::ITEMS_KEY][] = $currItemData; } } } @@ -109,11 +113,15 @@ private static function getItemDataFromInnerHits($elasticObject, &$itemData) private static function getInnerHitsObjectType($innerHitsKey) { - if(isset(self::$innerHitsObjectType[$innerHitsKey])) - return self::$innerHitsObjectType[$innerHitsKey]; + $queryNames = explode(ESearchNestedObjectItem::QUERY_NAME_DELIMITER, $innerHitsKey); + $objectType = $queryNames[0]; + $objectSubType = ($queryNames[1] != ESearchNestedObjectItem::DEFAULT_GROUP_NAME) ? $queryNames[1] : null; + + if(isset(self::$innerHitsObjectType[$objectType])) + return array(self::$innerHitsObjectType[$objectType], $objectSubType); KalturaLog::err('Unsupported inner object key in elastic results['.$innerHitsKey.']'); - return $innerHitsKey; + return array($objectType, $objectSubType); } private static function getItemsDataResult($objectType, $values) @@ -145,12 +153,20 @@ private static function getInnerHitsTotalCountForObject($objectResult, $objectTy } } - private static function pruneHighlight($highlight) + private static function elasticHighlightToCoreHighlight($eHighlight) { - if(isset($highlight)) + if(isset($eHighlight)) { - $keys = array_keys($highlight); - return $highlight[$keys[0]][0]; + $result = array(); + foreach ($eHighlight as $key => $value) + { + $resultType = new ESearchHighlight(); + $resultType->setFieldName($key); + $resultType->setHits($value); + $result[] = $resultType; + } + + return $result; } return null; diff --git a/plugins/search/providers/elastic_search/lib/model/ESearchQueryAttributes.php b/plugins/search/providers/elastic_search/lib/model/search/ESearchQueryAttributes.php similarity index 72% rename from plugins/search/providers/elastic_search/lib/model/ESearchQueryAttributes.php rename to plugins/search/providers/elastic_search/lib/model/search/ESearchQueryAttributes.php index 74e9458abd4..bd0c45b6cca 100644 --- a/plugins/search/providers/elastic_search/lib/model/ESearchQueryAttributes.php +++ b/plugins/search/providers/elastic_search/lib/model/search/ESearchQueryAttributes.php @@ -1,7 +1,7 @@ objectId; + } + + /** + * @param string $objectId + */ + public function setObjectId($objectId) + { + $this->objectId = $objectId; + } + + /** + * @return boolean + */ + public function getShouldUseDisplayInSearch() + { + return $this->shouldUseDisplayInSearch; + } + + /** + * @param boolean $shouldUseDisplayInSearch + */ + public function setShouldUseDisplayInSearch($shouldUseDisplayInSearch) + { + $this->shouldUseDisplayInSearch = $shouldUseDisplayInSearch; + } + + /** + * @var bool + */ + protected $shouldUseDisplayInSearch; + /** * @var array */ diff --git a/plugins/search/providers/elastic_search/lib/search/kBaseSearch.php b/plugins/search/providers/elastic_search/lib/model/search/kBaseSearch.php similarity index 84% rename from plugins/search/providers/elastic_search/lib/search/kBaseSearch.php rename to plugins/search/providers/elastic_search/lib/model/search/kBaseSearch.php index 7d2644e48dc..eccd7c1551f 100644 --- a/plugins/search/providers/elastic_search/lib/search/kBaseSearch.php +++ b/plugins/search/providers/elastic_search/lib/model/search/kBaseSearch.php @@ -1,7 +1,7 @@ elasticClient = new elasticClient(); $this->queryAttributes = new ESearchQueryAttributes(); + $this->mainBoolQuery = new kESearchBoolQuery(); } public abstract function doSearch(ESearchOperator $eSearchOperator, $statuses = array(), $objectId, kPager $pager = null, ESearchOrderBy $order = null, $useHighlight = true); public abstract function getPeerName(); + public abstract function getPeerRetrieveFunctionName(); + + protected function handleDisplayInSearch() + { + } + protected function execSearch(ESearchOperator $eSearchOperator) { $subQuery = $eSearchOperator->createSearchQuery($eSearchOperator->getSearchItems(), null, $this->queryAttributes, $eSearchOperator->getOperator()); - $this->applyElasticSearchConditions($subQuery); + $this->handleDisplayInSearch(); + $this->mainBoolQuery->addToMust($subQuery); + $this->applyElasticSearchConditions(); $this->addGlobalHighlights(); KalturaLog::debug("Elasticsearch query [".print_r($this->query, true)."]"); $result = $this->elasticClient->search($this->query); @@ -87,15 +97,14 @@ protected function initBaseFilter($partnerId, array $statuses, $objectId) $partnerStatus[] = elasticSearchUtils::formatPartnerStatus($partnerId, $status); } - $this->query['body']['query']['bool']['filter'][] = array( - 'terms' => array('partner_status' => $partnerStatus) - ); - + $partnerStatusQuery = new kESearchTermsQuery('partner_status', $partnerStatus); + $this->mainBoolQuery->addToFilter($partnerStatusQuery); + if($objectId) { - $this->query['body']['query']['bool']['filter'][] = array( - 'term' => array('_id' => elasticSearchUtils::formatSearchTerm($objectId)) - ); + $id = elasticSearchUtils::formatSearchTerm($objectId); + $idQuery = new kESearchTermQuery('_id', $id); + $this->mainBoolQuery->addToFilter($idQuery); } //return only the object id @@ -131,15 +140,17 @@ public static function getHighlightSection($configKey, $queryAttributes) return $highlight; } - protected function applyElasticSearchConditions($conditions) + protected function applyElasticSearchConditions() { - $this->query['body']['query']['bool']['must'] = array($conditions); + $this->query['body']['query'] = $this->mainBoolQuery->getFinalQuery(); } protected function initQueryAttributes($partnerId, $objectId, $useHighlight) { $this->initPartnerLanguages($partnerId); $this->queryAttributes->setUseHighlight($useHighlight); + $this->queryAttributes->setObjectId($objectId); + $this->queryAttributes->setShouldUseDisplayInSearch(true); $this->initOverrideInnerHits($objectId); } diff --git a/plugins/search/providers/elastic_search/lib/search/kCategorySearch.php b/plugins/search/providers/elastic_search/lib/model/search/kCategorySearch.php similarity index 85% rename from plugins/search/providers/elastic_search/lib/search/kCategorySearch.php rename to plugins/search/providers/elastic_search/lib/model/search/kCategorySearch.php index f889b35da32..13cf755823b 100644 --- a/plugins/search/providers/elastic_search/lib/search/kCategorySearch.php +++ b/plugins/search/providers/elastic_search/lib/model/search/kCategorySearch.php @@ -1,12 +1,13 @@ getSearchTerm(); - $multiMatch[self::BOOL_KEY][self::SHOULD_KEY][0][self::MULTI_MATCH_KEY][self::FIELDS_KEY] = array( - $fieldName.'.'.self::RAW_FIELD_SUFFIX.'^'.$rawBoostFactor, - $fieldName.'^'.$multiMatchFieldBoostFactor, - ); - $multiMatch[self::BOOL_KEY][self::SHOULD_KEY][0][self::MULTI_MATCH_KEY][self::TYPE_KEY] = self::MOST_FIELDS; + $multiMatchQuery = new kESearchMultiMatchQuery(); + $multiMatchQuery->setQuery($searchItem->getSearchTerm()); + $multiMatchQuery->addToFields($fieldName.'.'.self::RAW_FIELD_SUFFIX.'^'.$rawBoostFactor); + $multiMatchQuery->addToFields($fieldName.'^'.$multiMatchFieldBoostFactor); $queryAttributes->addFieldToHighlight($fieldName.'.'.self::RAW_FIELD_SUFFIX); $queryAttributes->addFieldToHighlight($fieldName); @@ -74,70 +72,54 @@ public static function getMultiMatchQuery($searchItem, $fieldName, &$queryAttrib if($mappingLanguageField) { $languageFieldBoostFactor = self::LANGUAGE_FIELD_BOOST_FACTOR * $fieldBoostFactor; - $multiMatch[self::BOOL_KEY][self::SHOULD_KEY][0][self::MULTI_MATCH_KEY][self::FIELDS_KEY][] = $mappingLanguageField.'^'.$languageFieldBoostFactor; - $synonymField = elasticSearchUtils::getSynonymFieldName($language,$mappingLanguageField,elasticSearchUtils::DOT_FIELD_DELIMITER); + $multiMatchQuery->addToFields($mappingLanguageField.'^'.$languageFieldBoostFactor); $queryAttributes->addFieldToHighlight($mappingLanguageField); + $synonymField = elasticSearchUtils::getSynonymFieldName($language,$mappingLanguageField,elasticSearchUtils::DOT_FIELD_DELIMITER); + if($synonymField) - $multiMatch[self::BOOL_KEY][self::SHOULD_KEY][0][self::MULTI_MATCH_KEY][self::FIELDS_KEY][] = $synonymField; //don't boost + $multiMatchQuery->addToFields($synonymField);//don't boost } } } + $partialQuery->addToShould($multiMatchQuery); $trigramFieldName = $fieldName.'.'.self::NGRAMS_FIELD_SUFFIX; - $multiMatch[self::BOOL_KEY][self::SHOULD_KEY][1][self::MATCH_KEY][$trigramFieldName][self::QUERY_KEY] = $searchItem->getSearchTerm(); + $matchQuery = new kESearchMatchQuery($trigramFieldName, $searchItem->getSearchTerm()); $trigramPercentage = kConf::get('ngramPercentage', 'elastic', self::DEFAULT_TRIGRAM_PERCENTAGE); - $multiMatch[self::BOOL_KEY][self::SHOULD_KEY][1][self::MATCH_KEY][$trigramFieldName][self::MINIMUM_SHOULD_MATCH_KEY] = "$trigramPercentage%"; - $multiMatch[self::BOOL_KEY][self::MINIMUM_SHOULD_MATCH_KEY] = 1; + $matchQuery->setMinimumShouldMatch("$trigramPercentage%"); $queryAttributes->addFieldToHighlight($trigramFieldName); - return $multiMatch; + $partialQuery->addToShould($matchQuery); + + return $partialQuery; } public static function getExactMatchQuery($searchItem, $fieldName, $allowedSearchTypes, &$queryAttributes) { - $exactMatch = array(); - $queryType = self::TERM_KEY; - $searchValuePath = self::VALUE_KEY; - $fieldSuffix = ''; - - if (in_array(ESearchItemType::PARTIAL, $allowedSearchTypes[$fieldName])) - { - $queryType = self::MATCH_PHRASE_KEY; - $searchValuePath = self::QUERY_KEY; - } - $searchTerm = elasticSearchUtils::formatSearchTerm($searchItem->getSearchTerm()); $fieldBoostFactor = $searchItem::getFieldBoostFactor($fieldName); - $exactMatch[$queryType] = array - ( - $fieldName . $fieldSuffix => array( - $searchValuePath => $searchTerm, - self::BOOST_KEY => $fieldBoostFactor - ) - ); + $fieldSuffix = ''; + $queryObject = 'kESearchTermQuery'; + if(in_array(ESearchItemType::PARTIAL, $allowedSearchTypes[$fieldName])) + $queryObject = 'kESearchMatchPhraseQuery'; + + $exactMatch = new $queryObject($fieldName, $searchTerm); + $exactMatch->setBoostFactor($fieldBoostFactor); $queryAttributes->addFieldToHighlight($fieldName . $fieldSuffix); + return $exactMatch; } public static function getPrefixQuery($searchItem, $fieldName, $allowedSearchTypes, &$queryAttributes) { - $prefixQuery = array(); - $queryType = self::PREFIX_KEY; $fieldSuffix = ''; - if(in_array(ESearchItemType::PARTIAL, $allowedSearchTypes[$fieldName])) $fieldSuffix = '.'.self::RAW_FIELD_SUFFIX; $searchTerm = elasticSearchUtils::formatSearchTerm($searchItem->getSearchTerm()); $fieldBoostFactor = $searchItem::getFieldBoostFactor($fieldName); - $prefixQuery[$queryType] = array - ( - $fieldName . $fieldSuffix => array - ( - self::VALUE_KEY => $searchTerm, - self::BOOST_KEY => $fieldBoostFactor - ) - ); + $prefixQuery = new kESearchPrefixQuery($fieldName . $fieldSuffix, $searchTerm); + $prefixQuery->setBoostFactor($fieldBoostFactor); $queryAttributes->addFieldToHighlight($fieldName . $fieldSuffix); return $prefixQuery; } @@ -147,31 +129,16 @@ public static function getRangeQuery($searchItem, $fieldName, $allowedSearchType $rangeObject = $searchItem->getRange(); if(!$rangeObject) return null; - /**@var $rangeObject ESearchRange*/ - $rangeSubQuery = array(); - $rangeQuery = array(); - $queryType = self::RANGE_KEY; - if(is_numeric($rangeObject->getGreaterThan())) - $rangeSubQuery[self::GT_KEY] = $rangeObject->getGreaterThan(); - if(is_numeric($rangeObject->getGreaterThanOrEqual())) - $rangeSubQuery[self::GTE_KEY] = $rangeObject->getGreaterThanOrEqual(); - if(is_numeric($rangeObject->getLessThan())) - $rangeSubQuery[self::LT_KEY] = $rangeObject->getLessThan(); - if(is_numeric($rangeObject->getLessThanOrEqual())) - $rangeSubQuery[self::LTE_KEY] = $rangeObject->getLessThanOrEqual(); - - $rangeQuery[$queryType][$fieldName] = $rangeSubQuery; + $rangeQuery = new kESearchRangeQuery($rangeObject, $fieldName); $queryAttributes->addFieldToHighlight($fieldName); return $rangeQuery; } public static function getExistsQuery($searchItem, $fieldName, $allowedSearchTypes, &$queryAttributes) { - $ExistsQuery = array(); - $queryType = self::EXISTS_KEY; - $ExistsQuery[$queryType][self::FIELD_KEY] = $fieldName; + $existsQuery = new kESearchExistsQuery($fieldName); $queryAttributes->addFieldToHighlight($fieldName); - return $ExistsQuery; + return $existsQuery; } } diff --git a/plugins/search/providers/elastic_search/lib/model/kESearchQueryParser.php b/plugins/search/providers/elastic_search/lib/model/search/kESearchQueryParser.php similarity index 97% rename from plugins/search/providers/elastic_search/lib/model/kESearchQueryParser.php rename to plugins/search/providers/elastic_search/lib/model/search/kESearchQueryParser.php index a53faadf90f..4312375de13 100644 --- a/plugins/search/providers/elastic_search/lib/model/kESearchQueryParser.php +++ b/plugins/search/providers/elastic_search/lib/model/search/kESearchQueryParser.php @@ -15,7 +15,7 @@ /** * @package plugins.elasticSearch - * @subpackage model + * @subpackage model.search */ class kESearchQueryParser { diff --git a/plugins/search/providers/elastic_search/lib/search/kEntrySearch.php b/plugins/search/providers/elastic_search/lib/model/search/kEntrySearch.php similarity index 55% rename from plugins/search/providers/elastic_search/lib/search/kEntrySearch.php rename to plugins/search/providers/elastic_search/lib/model/search/kEntrySearch.php index 15bb900f3c1..787edf3eeea 100644 --- a/plugins/search/providers/elastic_search/lib/search/kEntrySearch.php +++ b/plugins/search/providers/elastic_search/lib/model/search/kEntrySearch.php @@ -1,22 +1,17 @@ queryAttributes->getShouldUseDisplayInSearch()) + $this->initDisplayInSearch($this->queryAttributes->getObjectId()); + } + public function doSearch(ESearchOperator $eSearchOperator, $entriesStatus = array(), $objectId, kPager $pager = null, ESearchOrderBy $order = null, $useHighlight= true) { kEntryElasticEntitlement::init(); @@ -42,7 +43,6 @@ protected function initQuery(array $statuses, $objectId, kPager $pager = null, E 'type' => ElasticIndexMap::ELASTIC_ENTRY_TYPE ); $statuses = $this->initEntryStatuses($statuses); - $this->initDisplayInSearch($objectId); parent::initQuery($statuses, $objectId, $pager, $order, $useHighlight); } @@ -60,7 +60,8 @@ protected function initEntryStatuses($statuses) protected function initEntitlement() { - foreach (self::$entitlementContributors as $contributor) + $contributors = kEntryElasticEntitlement::getEntitlementContributors(); + foreach ($contributors as $contributor) { if($contributor::shouldContribute()) { @@ -77,45 +78,57 @@ protected function initEntryEntitlementQueries() if(kEntryElasticEntitlement::$parentEntitlement) { - $entitlementQueryPath = &$this->query['body']['query']['bool']['filter'][]; - //Validate that parent entry property exist - $entitlementQueryPath['bool']['should'][0]['bool']['filter'][]['exists']['field'] = 'parent_id'; + $EntitlementQueryBool = new kESearchBoolQuery(); - //assign by reference to create name alias - $this->parentEntryEntitlementQuery = &$entitlementQueryPath['bool']['should'][0]['bool']; + //Validate that parent entry property exist + $parentQueryBool = new kESearchBoolQuery(); + $parentExistQuery = new kESearchExistsQuery('parent_id'); + $parentQueryBool->addToFilter($parentExistQuery); + //assign by reference to create alias + $this->parentEntryEntitlementQuery = &$parentQueryBool; + $EntitlementQueryBool->addToShould($parentQueryBool); //Validate that parent entry property does not exist - $entitlementQueryPath['bool']['should'][1]['bool']['must_not'][]['exists']['field'] = 'parent_id'; - //assign by reference to create name alias - $this->entryEntitlementQuery = &$entitlementQueryPath['bool']['should'][1]['bool']; - $entitlementQueryPath['bool']['minimum_should_match'] = 1; + $entryQueryBool = new kESearchBoolQuery(); + $parentNotExistQuery = new kESearchExistsQuery('parent_id'); + $entryQueryBool->addToMustNot($parentNotExistQuery); + //assign by reference to create alias + $this->entryEntitlementQuery = &$entryQueryBool; + $EntitlementQueryBool->addToShould($entryQueryBool); + + //add to main query filter + $this->mainBoolQuery->addToFilter($EntitlementQueryBool); } else { - //entry query - assign by reference to create name alias - $this->entryEntitlementQuery = &$this->query['body']['query']['bool']['filter'][]['bool']; + $EntitlementQueryBool = new kESearchBoolQuery(); + //assign by reference to create alias + $this->entryEntitlementQuery = &$EntitlementQueryBool; + //add to main query filter + $this->mainBoolQuery->addToFilter($EntitlementQueryBool); } $this->isInitialized = true; } - function getPeerName() + public function getPeerName() { return self::PEER_NAME; } + public function getPeerRetrieveFunctionName() + { + return self::PEER_RETRIEVE_FUNCTION_NAME; + } + protected function initDisplayInSearch($objectId) { if($objectId) return; - - //add display in search to filter - $this->query['body']['query']['bool']['filter'][] = array( - 'bool' => array( - 'must_not' => array( - 'term' => array('display_in_search' => EntryDisplayInSearchType::SYSTEM) - ) - ) - ); + + $displayInSearchQuery = new kESearchTermQuery('display_in_search', EntryDisplayInSearchType::SYSTEM); + $displayInSearchBoolQuery = new kESearchBoolQuery(); + $displayInSearchBoolQuery->addToMustNot($displayInSearchQuery); + $this->mainBoolQuery->addToFilter($displayInSearchBoolQuery); } } diff --git a/plugins/search/providers/elastic_search/lib/search/kUserSearch.php b/plugins/search/providers/elastic_search/lib/model/search/kUserSearch.php similarity index 85% rename from plugins/search/providers/elastic_search/lib/search/kUserSearch.php rename to plugins/search/providers/elastic_search/lib/model/search/kUserSearch.php index 744b3a3cd96..4f2b629318b 100644 --- a/plugins/search/providers/elastic_search/lib/search/kUserSearch.php +++ b/plugins/search/providers/elastic_search/lib/model/search/kUserSearch.php @@ -1,12 +1,13 @@ fieldName; + } + + /** + * @param string $fieldName + */ + public function setFieldName($fieldName) + { + $this->fieldName = $fieldName; + } + + /** + * @return string + */ + public function getBoostFactor() + { + return $this->boostFactor; + } + + /** + * @param string $boostFactor + */ + public function setBoostFactor($boostFactor) + { + $this->boostFactor = $boostFactor; + } +} diff --git a/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchBaseQuery.php b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchBaseQuery.php new file mode 100644 index 00000000000..47e5469c8a3 --- /dev/null +++ b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchBaseQuery.php @@ -0,0 +1,11 @@ +boolQuery = array(); + $this->filterQueries = array(); + $this->mustQueries = array(); + $this->shouldQueries = array(); + $this->mustNotQueries = array(); + $this->minimumShouldMatch = 1; + } + + /** + * @return int + */ + public function getMinimumShouldMatch() + { + return $this->minimumShouldMatch; + } + + /** + * @param int $minimumShouldMatch + */ + public function setMinimumShouldMatch($minimumShouldMatch) + { + $this->minimumShouldMatch = $minimumShouldMatch; + } + + /** + * @return array + */ + public function getShouldQueries() + { + return $this->shouldQueries; + } + + public function addToFilter($query) + { + $this->filterQueries[] = $query; + } + + public function addToMust($query) + { + $this->mustQueries[] = $query; + } + + public function addToShould($query) + { + $this->shouldQueries[] = $query; + } + + public function addToMustNot($query) + { + $this->mustNotQueries[] = $query; + } + + public function getFinalQuery() + { + if($this->shouldAddToFinalQuery($this->filterQueries)) + $this->addToFinalQuery(self::FILTER_KEY, $this->filterQueries); + + if($this->shouldAddToFinalQuery($this->mustQueries)) + $this->addToFinalQuery(self::MUST_KEY, $this->mustQueries); + + if($this->shouldAddToFinalQuery($this->shouldQueries)) + { + $this->addToFinalQuery(self::SHOULD_KEY, $this->shouldQueries); + $this->boolQuery[self::BOOL_KEY][self::MINIMUM_SHOULD_MATCH_KEY] = $this->getMinimumShouldMatch(); + } + + if($this->shouldAddToFinalQuery($this->mustNotQueries)) + $this->addToFinalQuery(self::MUST_NOT_KEY,$this->mustNotQueries); + + return $this->boolQuery; + } + + public function addByOperatorType($boolOperator, $query) + { + switch ($boolOperator) + { + case self::MUST_KEY: + $this->addToMust($query); + break; + case self::FILTER_KEY: + $this->addToFilter($query); + break; + case self::MUST_NOT_KEY: + $this->addToMustNot($query); + break; + case self::SHOULD_KEY: + $this->addToShould($query); + break; + default: + KalturaLog::log("Undefined bool operator in kESearchBoolQuery[".$boolOperator."]"); + } + } + + private function shouldAddToFinalQuery($queriesPath) + { + if(count($queriesPath)) + return true; + + return false; + } + + private function addToFinalQuery($queryKey, $queriesPath) + { + foreach ($queriesPath as $query) + { + $this->boolQuery[self::BOOL_KEY][$queryKey][] = $query->getFinalQuery(); + } + } + +} diff --git a/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchCompoundQuery.php b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchCompoundQuery.php new file mode 100644 index 00000000000..9ff9324c49f --- /dev/null +++ b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchCompoundQuery.php @@ -0,0 +1,9 @@ +fieldName = $fieldName; + } + + public function getFinalQuery() + { + $query = array(); + $query[self::EXISTS_KEY][self::FIELD_KEY] = $this->fieldName; + return $query; + } +} diff --git a/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchMatchPhraseQuery.php b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchMatchPhraseQuery.php new file mode 100644 index 00000000000..5aa2271e5e3 --- /dev/null +++ b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchMatchPhraseQuery.php @@ -0,0 +1,31 @@ +fieldName = $fieldName; + $this->searchTerm = $searchTerm; + } + + public function getFinalQuery() + { + $query = array(); + $query[self::MATCH_PHRASE_KEY][$this->fieldName][self::QUERY_KEY] = $this->searchTerm; + if($this->getBoostFactor()) + $query[self::MATCH_PHRASE_KEY][$this->fieldName][self::BOOST_KEY] = $this->getBoostFactor(); + + return $query; + } +} diff --git a/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchMatchQuery.php b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchMatchQuery.php new file mode 100644 index 00000000000..a09f9e8b615 --- /dev/null +++ b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchMatchQuery.php @@ -0,0 +1,55 @@ +fieldName = $fieldName; + $this->searchTerm = $searchTerm; + } + + /** + * @return string + */ + public function getMinimumShouldMatch() + { + return $this->minimumShouldMatch; + } + + /** + * @param string $minimumShouldMatch + */ + public function setMinimumShouldMatch($minimumShouldMatch) + { + $this->minimumShouldMatch = $minimumShouldMatch; + } + + public function getFinalQuery() + { + $query = array(); + $query[self::MATCH_KEY][$this->fieldName][self::QUERY_KEY] = $this->searchTerm; + if($this->getBoostFactor()) + $query[self::MATCH_KEY][$this->fieldName][self::BOOST_KEY] = $this->getBoostFactor(); + if($this->minimumShouldMatch) + $query[self::MATCH_KEY][$this->fieldName][self::MINIMUM_SHOULD_MATCH_KEY] = $this->getMinimumShouldMatch(); + + return $query; + } +} diff --git a/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchMultiMatchQuery.php b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchMultiMatchQuery.php new file mode 100644 index 00000000000..01bc8286065 --- /dev/null +++ b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchMultiMatchQuery.php @@ -0,0 +1,86 @@ +fields = array(); + $this->type = self::MOST_FIELDS; + } + + /** + * @var array + */ + protected $fields; + + /** + * @var string + */ + protected $query; + + /** + * @var string + */ + protected $type; + + /** + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * @param string $type + */ + public function setType($type) + { + $this->type = $type; + } + + /** + * @return string + */ + public function getQuery() + { + return $this->query; + } + + /** + * @param string $query + */ + public function setQuery($query) + { + $this->query = $query; + } + + public function addToFields($fieldName) + { + $this->fields[] = $fieldName; + } + + public function getFinalQuery() + { + if(!count($this->fields)) + return null; + + $query[self::MULTI_MATCH_KEY][self::QUERY_KEY] = $this->getQuery(); + foreach ($this->fields as $field) + { + $query[self::MULTI_MATCH_KEY][self::FIELDS_KEY][] = $field; + } + $query[self::MULTI_MATCH_KEY][self::TYPE_KEY] = $this->getType(); + + return $query; + } +} diff --git a/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchNestedQuery.php b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchNestedQuery.php new file mode 100644 index 00000000000..982fd38cfed --- /dev/null +++ b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchNestedQuery.php @@ -0,0 +1,159 @@ +path; + } + + /** + * @param string $path + */ + public function setPath($path) + { + $this->path = $path; + } + + /** + * @return array + */ + public function getHighlight() + { + return $this->highlight; + } + + /** + * @param array $highlight + */ + public function setHighlight($highlight) + { + $this->highlight = $highlight; + } + + /** + * @return boolean + */ + public function getInnerHitsSource() + { + return $this->innerHitsSource; + } + + /** + * @param boolean $innerHitsSource + */ + public function setInnerHitsSource($innerHitsSource) + { + $this->innerHitsSource = $innerHitsSource; + } + + /** + * @return int + */ + public function getInnerHitsSize() + { + return $this->innerHitsSize; + } + + /** + * @param int $innerHitsSize + */ + public function setInnerHitsSize($innerHitsSize) + { + $this->innerHitsSize = $innerHitsSize; + } + + /** + * @return string + */ + public function getInnerHitsName() + { + return $this->innerHitsName; + } + + /** + * @param string $innerHitsName + */ + public function setInnerHitsName($innerHitsName) + { + $this->innerHitsName = $innerHitsName; + } + + /** + * @return mixed + */ + public function getQuery() + { + return $this->query; + } + + /** + * @param mixed $query + */ + public function setQuery($query) + { + $this->query = $query; + } + + public function getFinalQuery() + { + if(!$this->getQuery()) + return null; + + $query[self::NESTED_KEY][self::PATH_KEY] = $this->getPath(); + $query[self::NESTED_KEY][self::INNER_HITS_KEY][self::SIZE_KEY] = $this->getInnerHitsSize(); + $query[self::NESTED_KEY][self::INNER_HITS_KEY][self::SOURCE_KEY] = $this->getInnerHitsSource(); + $query[self::NESTED_KEY][self::QUERY_KEY] = $this->getQuery()->getFinalQuery(); + + if($this->getInnerHitsName()) + $query[self::NESTED_KEY][self::INNER_HITS_KEY][self::NAME_KEY] = $this->getInnerHitsName(); + + if($this->getHighlight()) + $query[self::NESTED_KEY][self::INNER_HITS_KEY][self::HIGHLIGHT_KEY] = $this->getHighlight(); + + return $query; + } +} diff --git a/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchPrefixQuery.php b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchPrefixQuery.php new file mode 100644 index 00000000000..d4211b2450f --- /dev/null +++ b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchPrefixQuery.php @@ -0,0 +1,31 @@ +fieldName = $fieldName; + $this->searchTerm = $searchTerm; + } + + public function getFinalQuery() + { + $query = array(); + $query[self::PREFIX_KEY][$this->fieldName][self::VALUE_KEY] = $this->searchTerm; + if($this->getBoostFactor()) + $query[self::PREFIX_KEY][$this->fieldName][self::BOOST_KEY] = $this->getBoostFactor(); + + return $query; + } +} diff --git a/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchRangeQuery.php b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchRangeQuery.php new file mode 100644 index 00000000000..867bacbb542 --- /dev/null +++ b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchRangeQuery.php @@ -0,0 +1,45 @@ +rangeObject = $rangeObject; + $this->fieldName = $fieldName; + } + + + public function getFinalQuery() + { + $rangeSubQuery = array(); + if(is_numeric($this->rangeObject->getGreaterThan())) + $rangeSubQuery[self::GT_KEY] = $this->rangeObject->getGreaterThan(); + if(is_numeric($this->rangeObject->getGreaterThanOrEqual())) + $rangeSubQuery[self::GTE_KEY] = $this->rangeObject->getGreaterThanOrEqual(); + if(is_numeric($this->rangeObject->getLessThan())) + $rangeSubQuery[self::LT_KEY] = $this->rangeObject->getLessThan(); + if(is_numeric($this->rangeObject->getLessThanOrEqual())) + $rangeSubQuery[self::LTE_KEY] = $this->rangeObject->getLessThanOrEqual(); + + $query[self::RANGE_KEY][$this->fieldName] = $rangeSubQuery; + + if($this->getBoostFactor()) + $query[self::RANGE_KEY][$this->fieldName][self::BOOST_KEY] = $this->getBoostFactor(); + + return $query; + } +} diff --git a/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchTermQuery.php b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchTermQuery.php new file mode 100644 index 00000000000..2b537a71cae --- /dev/null +++ b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchTermQuery.php @@ -0,0 +1,31 @@ +fieldName = $fieldName; + $this->searchTerm = $searchTerm; + } + + public function getFinalQuery() + { + $query = array(); + $query[self::TERM_KEY][$this->fieldName][self::VALUE_KEY] = $this->searchTerm; + if($this->getBoostFactor()) + $query[self::TERM_KEY][$this->fieldName][self::BOOST_KEY] = $this->getBoostFactor(); + + return $query; + } +} diff --git a/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchTermsQuery.php b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchTermsQuery.php new file mode 100644 index 00000000000..a356a8c10aa --- /dev/null +++ b/plugins/search/providers/elastic_search/lib/model/search/queries/kESearchTermsQuery.php @@ -0,0 +1,27 @@ +fieldName = $fieldName; + $this->searchTerms = $searchTerms; + } + + public function getFinalQuery() + { + $query = array(); + $query[self::TERMS_KEY][$this->fieldName] = $this->searchTerms; + return $query; + } +} diff --git a/plugins/search/providers/elastic_search/services/ESearchService.php b/plugins/search/providers/elastic_search/services/ESearchService.php index 50056e8fca2..447acb1c98c 100644 --- a/plugins/search/providers/elastic_search/services/ESearchService.php +++ b/plugins/search/providers/elastic_search/services/ESearchService.php @@ -126,7 +126,7 @@ private function initAndSearch($coreSearchObject, $searchParams, $pager) $this->handleSearchException($e); } - list($coreResults, $objectCount) = kESearchCoreAdapter::transformElasticToCoreObject($elasticResults, $coreSearchObject->getPeerName()); + list($coreResults, $objectCount) = kESearchCoreAdapter::transformElasticToCoreObject($elasticResults, $coreSearchObject->getPeerName(), $coreSearchObject->getPeerRetrieveFunctionName()); return array($coreResults, $objectCount); } diff --git a/plugins/transcoding/ismIndex/lib/KOperationEngineIsmManifest.php b/plugins/transcoding/ismIndex/lib/KOperationEngineIsmManifest.php index a4bcfacdedc..9b1ea4b9129 100644 --- a/plugins/transcoding/ismIndex/lib/KOperationEngineIsmManifest.php +++ b/plugins/transcoding/ismIndex/lib/KOperationEngineIsmManifest.php @@ -64,25 +64,26 @@ private function mergeIsmManifests($srcFileSyncs, $targetIsmcPath) $filePathMap = array(); foreach ($srcFileSyncs as $srcFileSync) { - $pair = null; + $tuple = array(); if(array_key_exists($srcFileSync->assetId, $filePathMap)) - $pair = $filePathMap[$srcFileSync->assetId]; - else - $pair = array(); + $tuple = $filePathMap[$srcFileSync->assetId]; + if($srcFileSync->fileSyncObjectSubType == 3) //ism file - $pair[0] = $srcFileSync->fileSyncLocalPath; + $tuple[0] = $srcFileSync->fileSyncLocalPath; else if($srcFileSync->fileSyncObjectSubType == 1 ) //ismv file - $pair[1] = $srcFileSync->fileSyncLocalPath; + $tuple[1] = $srcFileSync->fileSyncLocalPath; + $tuple[2] = $srcFileSync->fileEncryptionKey; - $filePathMap[$srcFileSync->assetId] = $pair; + $filePathMap[$srcFileSync->assetId] = $tuple; } - foreach ($filePathMap as $filePathPair) + foreach ($filePathMap as $filePathTuple) { - list($ismFilePath, $ismvFilePath) = $filePathPair; + list($ismFilePath, $ismvFilePath, $key) = $filePathTuple; if($ismFilePath) { - $xml = new SimpleXMLElement(file_get_contents($ismFilePath)); + $str = kEncryptFileUtils::getEncryptedFileContent($ismFilePath, $key, KBatchBase::getIV()); + $xml = new SimpleXMLElement($str); if(isset($xml->body->switch->video)) $xml->body->switch->video['src'] = basename($ismvFilePath); if(isset($xml->body->switch->audio)) $xml->body->switch->audio['src'] = basename($ismvFilePath); @@ -116,7 +117,7 @@ static private function mergeIsmcManifests(array $srcFileSyncs) $root = null; foreach ($srcFileSyncs as $srcFileSync) { if($srcFileSync->fileSyncObjectSubType == 4) { - $str = file_get_contents($srcFileSync->fileSyncLocalPath); + $str = kEncryptFileUtils::getEncryptedFileContent($srcFileSync->fileSyncLocalPath, $srcFileSync->fileEncryptionKey, KBatchBase::getIV()); $xml = new SimpleXMLElement($str); /* diff --git a/release-notes.md b/release-notes.md index 0fb9b0f0800..1a23d7b7ac0 100644 --- a/release-notes.md +++ b/release-notes.md @@ -1,3 +1,36 @@ +# Mercury 13.9.0 # + +## Explicit Live - allow only admin to view streams until they decide to show everyone ## +- Issue Type: Feature +- Issue ID: PLAT-7977 + +### Deployment scripts ### + + Deploy Explicit Live Push notification: + 1. Push notitifications: + First replacae all tokens from in the XML file below and remove ".template" from the fle name: + /opt/kaltura/app/deployment/updates/scripts/xml/notifications/explicit_live_notification.template.xml + + Run deployment script: + 1. remove existing notification template, through admin console, with system name EXPLICIT_LIVE_PUSH_NOTIFICATIONS if it exists + 2. php /opt/kaltura/app/deployment/updates/scripts/2017_10_22_deploy_explicit_live_push_notifications.php + +#### Known Issues & Limitations #### + + None. + +## Webcast - allow webcast producer to update cuepoint status ## +- Issue Type: Feature +- Issue ID: PLAT-8409 + +### Deployment scripts ### + + php /opt/kaltura/app/deployment/updates/scripts/add_permissions/2017_12_14_allow_webcast_producer_to_change_cue_point_status.php + +#### Known Issues & Limitations #### + + None. + # Mercury 13.8.0 # ## Add Recorded Entry replaced HTTP template ##