diff --git a/.gitignore b/.gitignore index be2c9e8a204..4b2eb5453aa 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,5 @@ coverage.xml ################## node_modules/ package-lock.json + +pype/premiere/ppro/js/debug.log diff --git a/pype/aport/__init__.py b/pype/aport/__init__.py deleted file mode 100644 index 9411470334e..00000000000 --- a/pype/aport/__init__.py +++ /dev/null @@ -1,122 +0,0 @@ -import os -import sys - -from avalon import api as avalon -from pyblish import api as pyblish -from app import api as app - -from .. import api -t = app.Templates() - -log = api.Logger.getLogger(__name__, "aport") - -AVALON_CONFIG = os.getenv("AVALON_CONFIG", "pype") - -ADDITIONAL_PLUGINS = ['ftrack'] - -PARENT_DIR = os.path.dirname(__file__) -PACKAGE_DIR = os.path.dirname(PARENT_DIR) -PLUGINS_DIR = os.path.join(PACKAGE_DIR, "plugins") - -PUBLISH_PATH = os.path.join( - PLUGINS_DIR, "aport", "publish" -).replace("\\", "/") - -if os.getenv("PUBLISH_PATH", None): - os.environ["PUBLISH_PATH"] = os.pathsep.join( - os.environ["PUBLISH_PATH"].split(os.pathsep) + - [PUBLISH_PATH] - ) -else: - os.environ["PUBLISH_PATH"] = PUBLISH_PATH - -LOAD_PATH = os.path.join(PLUGINS_DIR, "aport", "load") -CREATE_PATH = os.path.join(PLUGINS_DIR, "aport", "create") -INVENTORY_PATH = os.path.join(PLUGINS_DIR, "aport", "inventory") - - -def register_additional_plugin_paths(): - '''Adding additional host plugins - ''' - - for host in ADDITIONAL_PLUGINS: - publish_path = os.path.join( - PLUGINS_DIR, host, "publish").replace("\\", "/") - pyblish.register_plugin_path(publish_path) - - # adding path to PUBLISH_PATH environment - if os.getenv("PUBLISH_PATH", None): - os.environ["PUBLISH_PATH"] = os.pathsep.join( - os.environ["PUBLISH_PATH"].split(os.pathsep) + - [publish_path] - ) - else: - os.environ["PUBLISH_PATH"] = publish_path - - log.info( - "Registered additional plugin path: " - "{}".format(publish_path)) - - -def install(): - # api.set_avalon_workdir() - - log.info("Registering Aport plug-ins..") - pyblish.register_plugin_path(PUBLISH_PATH) - avalon.register_plugin_path(avalon.Loader, LOAD_PATH) - avalon.register_plugin_path(avalon.Creator, CREATE_PATH) - avalon.register_plugin_path(avalon.InventoryAction, INVENTORY_PATH) - - # additional plugins - register_additional_plugin_paths() - - # Disable all families except for the ones we explicitly want to see - family_states = [ - "imagesequence", - "mov" - - ] - avalon.data["familiesStateDefault"] = False - avalon.data["familiesStateToggled"] = family_states - - # load data from templates - api.load_data_from_templates() - - # launch pico server - pico_server_launch() - - -def uninstall(): - log.info("Deregistering Aport plug-ins..") - pyblish.deregister_plugin_path(PUBLISH_PATH) - avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH) - avalon.deregister_plugin_path(avalon.Creator, CREATE_PATH) - - # reset data from templates - api.reset_data_from_templates() - - -def pico_server_launch(): - # path = "C:/Users/hubert/CODE/github/pico/examples/everything" - path = os.path.join( - os.path.dirname(__file__), - # "package" - ) - - os.chdir(path) - print(os.getcwd()) - print(os.listdir(path)) - try: - args = [sys.executable, "-m", "pico.server", - # "pipeline", - "api" - ] - - app.forward( - args, - cwd=path - ) - except Exception as e: - log.error(e) - log.error(sys.exc_info()) - # sys.exit(returncode) diff --git a/pype/aport/api.py b/pype/aport/api.py deleted file mode 100644 index 8f0046b633b..00000000000 --- a/pype/aport/api.py +++ /dev/null @@ -1,225 +0,0 @@ -# api.py -import os -import sys - -import pico -from pico import PicoApp -from app.api import forward, Logger - -import pipeline as ppl - -log = Logger.getLogger(__name__, "aport") - - -@pico.expose() -def get_session(): - ppl.AVALON_PROJECT = os.getenv("AVALON_PROJECT", None) - ppl.AVALON_ASSET = os.getenv("AVALON_ASSET", None) - ppl.AVALON_TASK = os.getenv("AVALON_TASK", None) - ppl.AVALON_SILO = os.getenv("AVALON_SILO", None) - return ppl.get_session() - - -@pico.expose() -def load_representations(project, representations): - '''Querry data from mongo db for defined representations. - - Args: - project (str): name of the project - representations (list): representations which are required - - Returns: - data (dict): representations in last versions - - # testing url: - http://localhost:4242/api/load_representations?project=jakub_projectx&representations=[{%22asset%22:%22e09s031_0040%22,%22subset%22:%22referenceDefault%22,%22representation%22:%22mp4%22},%20{%22asset%22:%22e09s031_0030%22,%22subset%22:%22referenceDefault%22,%22representation%22:%22mp4%22}] - - # returning: - {"e09s031_0040_referenceDefault":{"_id":"5c6dabaa2af61756b02f7f32","schema":"pype:representation-2.0","type":"representation","parent":"5c6dabaa2af61756b02f7f31","name":"mp4","data":{"path":"C:\\Users\\hubert\\_PYPE_testing\\projects\\jakub_projectx\\thisFolder\\e09\\s031\\e09s031_0040\\publish\\clip\\referenceDefault\\v019\\jkprx_e09s031_0040_referenceDefault_v019.mp4","template":"{publish.root}/{publish.folder}/{version.main}/{publish.file}"},"dependencies":[],"context":{"root":"C:\\Users\\hubert\\_PYPE_testing\\projects","project":{"name":"jakub_projectx","code":"jkprx"},"task":"edit","silo":"thisFolder","asset":"e09s031_0040","family":"clip","subset":"referenceDefault","VERSION":19,"hierarchy":"thisFolder\\e09\\s031","representation":"mp4"}}} - ''' - data = {} - # log.info("___project: {}".format(project)) - # ppl.io.activate_project(project) - # - # from_mongo = ppl.io.find({"name": repr['representation'], - # "type": "representation"})[:] - - for repr in representations: - log.info("asset: {}".format(repr['asset'])) - # set context for each asset individually - context(project, repr['asset'], '') - - # query data from mongo db for the asset's subset representation - related_repr = [r for r in ppl.io.find({"name": repr['representation'], - "type": "representation", - "context.asset": repr['asset']})[:]] - - versions_dict = {r['context']['version']: i - for i, r in enumerate(related_repr)} - versions_list = [v for v in versions_dict.keys()] - sorted(versions_list) - - version_index_last = versions_dict[max(versions_list)] - - log.info("version_index_last: {}".format(version_index_last)) - # create name which will be used on timeline clip - name = '_'.join([repr['asset'], repr['subset']]) - - # log.info("___related_repr: {}".format(related_repr)) - # assign data for the clip representation - version = ppl.io.find_one( - {'_id': related_repr[version_index_last]['parent']}) - log.info("version: {}".format(version)) - - # fixing path workarround - if '.#####.mxf' in related_repr[version_index_last]['data']['path']: - related_repr[version_index_last]['data']['path'] = related_repr[version_index_last]['data']['path'].replace( - '.#####.mxf', '.mxf') - - related_repr[version_index_last]['version'] = version - related_repr[version_index_last]['parentClip'] = repr['parentClip'] - data[name] = related_repr[version_index_last] - - return data - - -@pico.expose() -def publish(send_json_path, get_json_path, gui): - """ - Runs standalone pyblish and adds link to - data in external json file - - It is necessary to run `register_plugin_path` if particular - host is needed - - Args: - send_json_path (string): path to temp json file with - sending context data - get_json_path (strign): path to temp json file with - returning context data - - Returns: - dict: get_json_path - - Raises: - Exception: description - - """ - - log.info("avalon.session is: \n{}".format(ppl.SESSION)) - log.info("PUBLISH_PATH: \n{}".format(os.environ["PUBLISH_PATH"])) - - pype_start = os.path.join(os.getenv('PYPE_SETUP_ROOT'), - "app", "pype-start.py") - - args = [pype_start, - "--root", os.environ['AVALON_PROJECTS'], "--publish-gui", - "-pp", os.environ["PUBLISH_PATH"], - "-d", "rqst_json_data_path", send_json_path, - "-d", "post_json_data_path", get_json_path - ] - - log.debug(args) - log.info("_aport.api Variable `AVALON_PROJECTS` had changed to `{0}`.".format( - os.environ['AVALON_PROJECTS'])) - forward([ - sys.executable, "-u" - ] + args, - # cwd=cwd - ) - - return {"get_json_path": get_json_path} - - -@pico.expose() -def context(project, asset, task, app='aport'): - os.environ["AVALON_PROJECT"] = ppl.AVALON_PROJECT = project - os.environ["AVALON_ASSET"] = ppl.AVALON_ASSET = asset - os.environ["AVALON_TASK"] = ppl.AVALON_TASK = task - os.environ["AVALON_SILO"] = ppl.AVALON_SILO = '' - - ppl.get_session() - # log.info('ppl.SESSION: {}'.format(ppl.SESSION)) - - # http://localhost:4242/pipeline/context?project=this&asset=shot01&task=comp - - ppl.update_current_task(task, asset, app) - - project_code = ppl.io.find_one({"type": "project"})["data"].get("code", '') - - os.environ["AVALON_PROJECTCODE"] = \ - ppl.SESSION["AVALON_PROJECTCODE"] = project_code - - parents = ppl.io.find_one({"type": 'asset', - "name": ppl.AVALON_ASSET})['data']['parents'] - - if parents and len(parents) > 0: - # hierarchy = os.path.sep.join(hierarchy) - hierarchy = os.path.join(*parents).replace("\\", "/") - - os.environ["AVALON_HIERARCHY"] = \ - ppl.SESSION["AVALON_HIERARCHY"] = hierarchy - - fix_paths = {k: v.replace("\\", "/") for k, v in ppl.SESSION.items() - if isinstance(v, str)} - - ppl.SESSION.update(fix_paths) - ppl.SESSION.update({"AVALON_HIERARCHY": hierarchy, - "AVALON_PROJECTCODE": project_code, - "current_dir": os.getcwd().replace("\\", "/") - }) - - return ppl.SESSION - - -@pico.expose() -def anatomy_fill(data): - from pype import api as pype - pype.load_data_from_templates() - anatomy = pype.Anatomy - return anatomy.format(data) - - -@pico.expose() -def deregister_plugin_path(): - if os.getenv("PUBLISH_PATH", None): - aport_plugin_path = os.pathsep.join( - [p.replace("\\", "/") - for p in os.environ["PUBLISH_PATH"].split(os.pathsep) - if "aport" in p or - "ftrack" in p]) - os.environ["PUBLISH_PATH"] = aport_plugin_path - else: - log.warning("deregister_plugin_path(): No PUBLISH_PATH is registred") - - return "Publish path deregistered" - - -@pico.expose() -def register_plugin_path(publish_path): - deregister_plugin_path() - if os.getenv("PUBLISH_PATH", None): - os.environ["PUBLISH_PATH"] = os.pathsep.join( - os.environ["PUBLISH_PATH"].split(os.pathsep) - + [publish_path.replace("\\", "/")] - ) - else: - os.environ["PUBLISH_PATH"] = publish_path - - log.info(os.environ["PUBLISH_PATH"].split(os.pathsep)) - - return "Publish registered paths: {}".format( - os.environ["PUBLISH_PATH"].split(os.pathsep) - ) - - -app = PicoApp() -app.register_module(__name__) - -# remove all Handlers created by pico -for name, handler in [(handler.get_name(), handler) - for handler in Logger.logging.root.handlers[:]]: - if "pype" not in str(name).lower(): - Logger.logging.root.removeHandler(handler) - -# SPLASH.hide_splash() diff --git a/pype/aport/lib.py b/pype/aport/lib.py deleted file mode 100644 index 34cfe62e3db..00000000000 --- a/pype/aport/lib.py +++ /dev/null @@ -1,26 +0,0 @@ -import pype.api as pype - - -def get_anatomy(**kwarg): - return pype.Anatomy - - -def format_anatomy(data): - from .templates import ( - get_anatomy - ) - file = script_name() - - anatomy = get_anatomy() - - # TODO: perhaps should be in try! - padding = anatomy.render.padding - - data.update({ - "hierarchy": pype.get_hierarchy(), - "frame": "#" * padding, - "VERSION": pype.get_version_from_workfile(file) - }) - - # log.info("format_anatomy:anatomy: {}".format(anatomy)) - return anatomy.format(data) diff --git a/pype/aport/pipeline.py b/pype/aport/pipeline.py deleted file mode 100644 index 7bacc936b6e..00000000000 --- a/pype/aport/pipeline.py +++ /dev/null @@ -1,130 +0,0 @@ -import sys -import os -import getpass - -from app.api import Logger -from io_nonsingleton import DbConnector - - -io = DbConnector() -log = Logger.getLogger(__name__, "aport") - -self = sys.modules[__name__] -self.SESSION = None -self._registered_root = {"_": ""} -self.AVALON_PROJECT = os.getenv("AVALON_PROJECT", None) -self.AVALON_ASSET = os.getenv("AVALON_ASSET", None) -self.AVALON_TASK = os.getenv("AVALON_TASK", None) -self.AVALON_SILO = os.getenv("AVALON_SILO", None) - - -def get_session(): - if not self.SESSION: - io.install() - self.SESSION = io.Session - - # for k, v in os.environ.items(): - # if 'AVALON' in k: - # print(str((k, v))) - - return self.SESSION - - -def update_current_task(task=None, asset=None, app=None): - """Update active Session to a new task work area. - - This updates the live Session to a different `asset`, `task` or `app`. - - Args: - task (str): The task to set. - asset (str): The asset to set. - app (str): The app to set. - - Returns: - dict: The changed key, values in the current Session. - - """ - - mapping = { - "AVALON_ASSET": asset, - "AVALON_TASK": task, - "AVALON_APP": app, - } - changed = {key: value for key, value in mapping.items() if value} - if not changed: - return - - # Update silo when asset changed - if "AVALON_ASSET" in changed: - asset_document = io.find_one({"name": changed["AVALON_ASSET"], - "type": "asset"}) - assert asset_document, "Asset must exist" - silo = asset_document["silo"] - if silo is None: - silo = asset_document["name"] - changed["AVALON_SILO"] = silo - parents = asset_document['data']['parents'] - hierarchy = "" - if len(parents) > 0: - hierarchy = os.path.sep.join(parents) - changed['AVALON_HIERARCHY'] = hierarchy - - # Compute work directory (with the temporary changed session so far) - project = io.find_one({"type": "project"}, - projection={"config.template.work": True}) - template = project["config"]["template"]["work"] - _session = self.SESSION.copy() - _session.update(changed) - changed["AVALON_WORKDIR"] = _format_work_template(template, _session) - - # Update the full session in one go to avoid half updates - self.SESSION.update(changed) - - # Update the environment - os.environ.update(changed) - - return changed - - -def _format_work_template(template, session=None): - """Return a formatted configuration template with a Session. - - Note: This *cannot* format the templates for published files since the - session does not hold the context for a published file. Instead use - `get_representation_path` to parse the full path to a published file. - - Args: - template (str): The template to format. - session (dict, Optional): The Session to use. If not provided use the - currently active global Session. - - Returns: - str: The fully formatted path. - - """ - if session is None: - session = self.SESSION - - project = io.find_one({'type': 'project'}) - - return template.format(**{ - "root": registered_root(), - "project": { - "name": project.get("name", session["AVALON_PROJECT"]), - "code": project["data"].get("code", ''), - }, - "silo": session["AVALON_SILO"], - "hierarchy": session['AVALON_HIERARCHY'], - "asset": session["AVALON_ASSET"], - "task": session["AVALON_TASK"], - "app": session["AVALON_APP"], - "user": session.get("AVALON_USER", getpass.getuser()) - }) - - -def registered_root(): - """Return currently registered root""" - return os.path.normpath( - self._registered_root["_"] - or self.SESSION.get("AVALON_PROJECTS") or "" - ) diff --git a/pype/aport/static/build.js b/pype/aport/static/build.js deleted file mode 100644 index 180c65d29cb..00000000000 --- a/pype/aport/static/build.js +++ /dev/null @@ -1,4862 +0,0 @@ -var app = angular.module("Plugin", ["ui-rangeSlider", "ui.bootstrap"]); -app.run(["$rootScope", "MainHelper", function($rootScope, MainHelper) { - MainHelper.init(BM_VIDEO, 15) -}]), app.controller("ModalIntroController", function($scope, $uibModal, CreateOnFileSystemService, DestinationsService) { - $scope.items = [], $scope.obj = { - state: 1 - }, $scope.$root.$on("intro requested", function(event) { - console.log("ModalIntroController event handler"), $scope.open("sm") - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_INTRO_HTML, - backdrop: "static", - controller: ModalIntroInstanceCtrl, - windowClass: "modal-intro" - }).result.then(function() { - console.log("ModalIntroController OK"), CreateOnFileSystemService.createDestinationBaseFolder(), DestinationsService.saveItem() - }, function() { - console.log("ModalIntroController CANCELED") - }) - } -}); - -var ModalIntroInstanceCtrl = function($scope, $uibModalInstance, BrowseDestinationService, AppModel) { - $scope.obj = { - state: 1, - title: "", - message: "", - labelLeft: [!1, "PREVIOUS"], - labelCenter: [!1, ""], - labelRight: [!0, "NEXT"], - stateImage: [!0, ""], - selectedFolder: AppModel.currentBaseFolder - }, $scope.onChange = function() { - switch (1 < $scope.obj.state && ($scope.obj.stateImage = [!0, STATE_IMG + $scope.obj.state + ".png"]), $scope.obj.state) { - case 1: - $scope.obj.stateName = "", $scope.obj.stateImage = [!1, ""], $scope.obj.labelLeft = [!1, "PREVIOUS"], $scope.obj.title = "Welcome!", $scope.obj.message = "Thanks for downloading the Pond5 Adobe Add-On.
Click through this short tutorial to learn some of the basics."; - break; - case 2: - $scope.obj.labelLeft = [!0, "PREVIOUS"], $scope.obj.stateName = "search", $scope.obj.title = "", $scope.obj.message = "Start by searching our massive library of royalty-free video clips
and easily add them to your working projects."; - break; - case 3: - $scope.obj.stateName = "filters", $scope.obj.labelLeft = [!0, "PREVIOUS"], $scope.obj.message = "Use the toolbar on the left to filter your search results,
view your previews, and update your directory folder."; - break; - case 4: - $scope.obj.stateName = "collections", $scope.obj.message = "View and create new collections below.
We've even added 50 free clips to get you started!"; - break; - case 5: - $scope.obj.stateName = "login", $scope.obj.labelCenter = [!1, "SELECT"], $scope.obj.labelRight = [!0, "NEXT"], $scope.obj.message = "Log in to your Pond5 account here for easy checkout
once you've found the perfect clips for your project."; - break; - case 6: - $scope.obj.stateName = "", $scope.obj.labelLeft = [!0, "PREVIOUS"], $scope.obj.labelCenter = [!0, "SELECT"], $scope.obj.labelRight = [!0, "FINISH"], $scope.obj.message = "Select your destination folder to get started. Pond5 media will be saved in this folder.", 0 < AppModel.currentBaseFolder.length && ($scope.obj.message = "Select your destination folder to get started.
The default folder is " + AppModel.currentBaseFolder) - } - }, $scope.buttonLeftClicked = function() { - $scope.obj.state--, $scope.onChange(), getStateObject($scope.obj.stateName) - }, $scope.buttonCenterClicked = function() { - $scope.obj.selectedFolder = BrowseDestinationService.browse(), $scope.obj.message = "Your current destination folder is:
" + $scope.obj.selectedFolder - }, $scope.buttonRightClicked = function() { - console.log("ModalIntroController buttonRightClicked"), $scope.obj.state < 6 ? ($scope.obj.state++, $scope.onChange(), getStateObject($scope.obj.stateName)) : (console.log("ModalIntroController buttonRightClicked", $scope.obj.selectedFolder), BrowseDestinationService.save($scope.obj.selectedFolder), $uibModalInstance.close()) - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel") - }, getStateObject = function(stateName) { - console.log("modalIntroController look for: ", stateName), INTRO_DATA.forEach(function(entry) { - var obj = {}; - entry.stateName === stateName ? (console.log("modalIntroController found stateName: ", entry), obj.stateName = entry.stateName, obj.arrowClass = entry.arrowClass, obj.posX = entry.posX, obj.posY = entry.posY, console.log("modalIntroController found obj: ", obj)) : (obj.stateName = stateName, obj.arrowClass = ""), $scope.$root.$emit("intro asset requested", obj) - }) - }, $scope.onChange() -}; -PLUGIN_VERSION = "", HOST_NAME = "PPRO", THIRD_PARTY = "", MEDIA_TYPES = ["Footage", "Music", "SFX"], BUTTON_REPLACE_LABEL = "REPLACE WITH HI-RES CLIPS", BUTTON_REPLACE_TOOLTIP = "Replace lo-res with paid items", MODAL_REPLACE_HEADER = "Replace With Hi-Res Clips", MODAL_REPLACE_CONTENT = "The selected items below will be replaced by full resolution versions after you complete checkout. Items already in your account history will also be downloaded.", MODAL_REPLACE_RES_TITLE = "RESOLUTION", MODAL_INTRO_SEARCH = "Start by searching our massive library of royalty-free video clips
and easily add them to your working projects.", MODAL_INTRO_COLLECTIONS = "View and create new collections below.
We've even added 50 free clips to get you started!", MODAL_INTRO_LOGIN = "Log in to your Pond5 account here for easy checkout
once you've found the perfect clips for your project.", INTRO_DATA = [{ - state: 7, - stateName: "downloads", - arrowClass: ".intro-asset-arrow-left", - posY: ["top", "96px"], - posX: ["left", "60px"] -}, { - state: 3, - stateName: "filters", - arrowClass: ".intro-asset-arrow-left", - posY: ["top", "60px"], - posX: ["left", "55px"] -}, { - state: 9, - stateName: "destination", - arrowClass: ".intro-asset-arrow-left", - posY: ["bottom", "55px"], - posX: ["left", "60px"] -}, { - state: 4, - stateName: "collections", - arrowClass: ".intro-asset-arrow-down", - posY: ["bottom", "140px"], - posX: ["left", "260px"] -}, { - state: 2, - stateName: "search", - arrowClass: ".intro-asset-arrow-up", - posY: ["top", "60px"], - posX: ["left", "165px"] -}, { - state: 5, - stateName: "login", - arrowClass: ".intro-asset-arrow-up", - posY: ["top", "60px"], - posX: ["right", "75px"] -}], app.service("ReplaceService", ["$rootScope", "ReplaceModel", "Service", "ReplaceServiceShared", function($rootScope, ReplaceModel, Service, ReplaceServiceShared) { - var call = { - onClipFSCollected: function() { - call.getSequences() - }, - getSequences: function() { - csInterface.evalScript("getSequences()", function(result) { - var sequences = JSON.parse(result).sequences; - console.log("\nReplaceService sequences NEW", sequences.length, sequences), ReplaceModel.setSequences(sequences) - }) - }, - getMedia: function() { - var obj = ReplaceModel.sequences; - csInterface.evalScript("getSequenceItems(" + JSON.stringify(obj) + ")", function(result) { - var clipsInSequences = JSON.parse(result).data; - ReplaceModel.clipsInSequences = clipsInSequences, console.log("\nReplaceService clipsInSequences", ReplaceModel.clipsInSequences), csInterface.evalScript("getProjectItems()", function(result) { - call.getMissingItemIDs() - }) - }) - }, - getClipsInSelectedSequences: function() { - for (var clipsInSequences = ReplaceModel.clipsInSequences, clipsInSelectedSequences = [], s = 0; s < ReplaceModel.sequences.length; s++) - for (var j = 0; j < clipsInSequences.length; j++) - if (ReplaceModel.sequences[s].sequenceID === clipsInSequences[j].sequenceID && ReplaceModel.sequences[s].checked) - for (var k = 0; k < clipsInSequences[j].clipNames.length; k++) clipsInSelectedSequences.push(clipsInSequences[j].clipNames[k]); - return clipsInSelectedSequences - }, - getMissingItemIDs: function() { - var clipsInSelectedSequences = call.getClipsInSelectedSequences(); - clipsInSelectedSequences = ReplaceServiceShared.removeDuplicates(clipsInSelectedSequences), console.log("\nReplaceService clipsInSelectedSequences after removing duplicates: ", clipsInSelectedSequences); - var previewNamesonFS = ReplaceServiceShared.getPreviewsOnFSNames(); - clipsInSelectedSequences = ReplaceServiceShared.filterNonP5Clips(clipsInSelectedSequences, previewNamesonFS), console.log("\nReplaceService after filterNonP5Clips", clipsInSelectedSequences); - var previewIDs = ReplaceServiceShared.getPreviewsIDs(clipsInSelectedSequences); - console.log("\nReplaceService previewIDs: " + previewIDs), ReplaceServiceShared.setReplaceProp(previewIDs), console.log("\nReplaceService after set replace: " + ReplaceModel.hiresOnFS); - var hiresIDs = ReplaceServiceShared.getHiresIDsonFS(); - console.log("\nReplaceService hiresIDs: " + hiresIDs); - var missingItemIDs = _(previewIDs).difference(hiresIDs), - missingIDsToString = missingItemIDs.join(","); - 0 < missingItemIDs.length ? Service.getMissingItems(missingIDsToString) : 0 < hiresIDs.length ? call.onPurchasedAndDownloaded() : 0 === clipsInSelectedSequences.length && (ReplaceModel.setState(DEFAULT), $rootScope.$emit("modal simple requested", ["", "There are are currently no Pond5 previews in the sequence(s) you've selected."])) - }, - onPurchasedAndDownloaded: function() { - var hasReplaceCandidates = !1; - if (ReplaceModel.hiresOnFS.forEach(function(entry) { - entry.replace && (hasReplaceCandidates = !0) - }), !hasReplaceCandidates) return $rootScope.$emit("modal simple requested", ["", "Replacing previews by hi-res clips has been canceled"]), void ReplaceModel.setState(DEFAULT); - var obj = { - hiresOnFS: ReplaceModel.hiresOnFS - }; - csInterface.evalScript("replaceClips(" + JSON.stringify(obj) + ")", function(result) { - $rootScope.$emit("modal simple requested", ["", "Your previews have been successfully replaced by your purchased clips. Right-click the clips and choose Scale to Frame Size to scale them correctly."]), ReplaceModel.setState(DEFAULT) - }) - } - }; - return call -}]), app.controller("ModalAddDestinationController", function($scope, $uibModal, UserModel, AppModel, CreateOnFileSystemService, DestinationsService) { - $scope.obj = {}, $scope.$root.$on("modal add destination requested", function() { - console.log("ModalAddDestinationController event handler", UserModel.getFirstTimeUser()), $scope.obj.title = "Add a destination folder", $scope.obj.content = "Please select a new folder to store your previews and purchased items.", $scope.obj.okButtonLabel = "APPLY", $scope.obj.selectedFolderPrefix = "Current folder: ", $scope.obj.selectedFolder = AppModel.currentBaseFolder, $scope.open("lg") - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_ADD_DESTINATION_HTML, - controller: ModalAddDestinatonInstanceCtrl, - size: size, - resolve: { - obj: function() { - return $scope.obj - } - } - }).result.then(function() { - console.log("ModalAddDestinationController OK", AppModel.currentBaseFolder), $scope.onClicked() - }, function() { - console.log("ModalAddDestinationController CANCEL", AppModel.currentBaseFolder), $scope.onClicked() - }) - }, $scope.onClicked = function() { - console.log("ModalAddDestinationController onClicked"), UserModel.getFirstTimeUser() && $scope.$root.$emit("modal freebies"), CreateOnFileSystemService.createDestinationBaseFolder(), DestinationsService.saveItem() - } -}); -var ModalAddDestinatonInstanceCtrl = function($scope, $uibModalInstance, obj, BrowseDestinationService) { - $scope.obj = {}, $scope.obj.showTitle = obj.showTitle, $scope.obj.title = obj.title, $scope.obj.content = obj.content, $scope.obj.selectedFolder = obj.selectedFolder, $scope.obj.selectedFolderPrefix = obj.selectedFolderPrefix, $scope.obj.okButtonLabel = obj.okButtonLabel, $scope.browse = function() { - console.log("ModalAddDestinatonInstanceCtrl browse"), $scope.obj.selectedFolder = BrowseDestinationService.browse() - }, $scope.ok = function() { - BrowseDestinationService.save($scope.obj.selectedFolder), $uibModalInstance.close() - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel") - } -}; -app.controller("ModalSelectSequencesController", function($scope, $uibModal, ReplaceModel, ReplaceService) { - $scope.items = [], $scope.$root.$on("modal select sequences", function(event, data) { - $scope.items = data, $scope.open("lg") - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_SELECT_SEQUENCES_HTML, - controller: ModalSelectSequencesInstanceCtrl, - size: size, - resolve: { - items: function() { - return $scope.items - } - } - }).result.then(function() { - console.log("ModalSelectSequencesController OK: ", $scope.items); - for (var i = 0; i < $scope.items.length; i++) $scope.items[i].selected && (ReplaceModel.sequences[i].checked = !0); - ReplaceService.getMedia() - }, function() { - ReplaceModel.setState(DEFAULT) - }) - } -}); -var ModalSelectSequencesInstanceCtrl = function($scope, $uibModalInstance, items) { - $scope.items = items, $scope.obj = { - showWarning: !1 - }, $scope.ok = function() { - for (var checked = !1, i = 0; i < $scope.items.length; i++) $scope.items[i].selected && (checked = !0); - checked ? $uibModalInstance.close() : $scope.obj.showWarning = !0 - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel") - } -}; -app.factory("MainHelper", ["$rootScope", "AppModel", "StartUpService", "SearchModel", function($rootScope, AppModel, StartUpService, SearchModel) { - var result = { - init: function(mediaType, sumOfBitmasks) { - csInterface = new CSInterface, csInterface.addEventListener("LogEvent", function(evt) { - console.log("JSX : " + evt.data) - }); - var rootFolderPath = csInterface.getSystemPath(SystemPath.EXTENSION); - AppModel.rootFolderPath = rootFolderPath, fs = require("fs"), os = require("os"), path = require("path"), url = require("url"), https = require("https"), xml2js = require(rootFolderPath + "/node_modules/xml2js/lib/xml2js.js"), walk = require(rootFolderPath + "/node_modules/walk/lib/walk.js"), junk = require(rootFolderPath + "/node_modules/junk/index.js"), rimraf = require(rootFolderPath + "/node_modules/rimraf/rimraf.js"), opn = require(rootFolderPath + "/node_modules/opn/index.js"), DecompressZip = require(rootFolderPath + "/node_modules/decompress-zip/lib/decompress-zip.js"), $("#logo").click(function() { - location.reload() - }), result.readManifestXML(), SearchModel.sumOfBitmasks = sumOfBitmasks, $rootScope.$emit("media filter change", mediaType), setTimeout(function() { - AppModel.setEnv() - }, 2e3) - }, - readManifestXML: function() { - var file = AppModel.rootFolderPath + "/CSXS/manifest.xml"; - fs.readFile(file, "utf8", function(err, data) { - if (err) throw err; - result.parseXML(data) - }) - }, - parseXML: function(xml) { - var parser = new xml2js.Parser; - parser.addListener("end", function(res) { - PLUGIN_VERSION = res.ExtensionManifest.$.ExtensionBundleVersion, console.log("mainHelper parsed manifest xml, version:", PLUGIN_VERSION), result.loadJSX() - }), parser.parseString(xml) - }, - loadJSX: function(fileName) { - var jsxPath = AppModel.rootFolderPath + "/jsx/json2.js"; - console.log("mainHelper loadJSX:", jsxPath), csInterface.evalScript('$.evalFile("' + jsxPath + '")', function(result) {}) - } - }; - return result -}]), app.service("BrowseDestinationService", ["AppModel", function(AppModel) { - this.browse = function() { - var result = window.cep.fs.showOpenDialog(!1, !0, "Select a folder for your previews and hi-res downloads.", ""), - selectedFolder = AppModel.currentBaseFolder; - return console.log("BrowseDestinationService folder chosen, result.err: ", result.err), 0 == result.err ? (console.log("BrowseDestinationService folder chosen: ", result.data[0]), result.data[0] && (selectedFolder = result.data[0])) : selectedFolder = "This folder cannot be selected. Please choose another folder.", console.log("BrowseDestinationService return folder: ", selectedFolder), selectedFolder - }, this.save = function(selectedFolder) { - console.log("BrowseDestinationService save", AppModel.getOS(), "win" === AppModel.getOS()), "win" === AppModel.getOS() ? AppModel.currentBaseFolder = selectedFolder.replace(/\//g, "\\") : AppModel.currentBaseFolder = selectedFolder - } -}]), app.service("CreateFileCompleteService", ["ImportedPreviewsService", "DestinationsService", "UserService", function(ImportedPreviewsService, DestinationsService, UserService) { - return { - onFileReady: function(file) { - -1 != file.indexOf("imported_previews.xml") && ImportedPreviewsService.readXML(), -1 != file.indexOf("destinations.xml") && DestinationsService.readXML(), -1 != file.indexOf("user.xml") && UserService.readXML() - } - } -}]), app.factory("DestinationsService", ["$rootScope", "AppModel", "UserModel", function($rootScope, AppModel, UserModel) { - var result = { - xmlVersion: "", - readXML: function() { - result.file = AppModel.getDestinationsXML(), console.log("DestinationsService file: ", result.file), fs.readFile(result.file, "utf8", function(err, data) { - if (err) throw err; - result.xml = data, console.log("DestinationsService, xml:", result.xml), result.parseXML() - }) - }, - saveItem: function() { - var node = ''; - result.xml = result.xml.insert(result.xml.indexOf("destinations") + 13, node), result.writeToDisk() - }, - deleteItem: function() {}, - parseXML: function() { - var parser = new xml2js.Parser; - parser.addListener("end", function(res) { - var i; - result.parsedXML = res, AppModel.baseFolders = [], UserModel.setFirstTimeUser(!1), res.root.$[HOST_NAME] ? result.xmlVersion = res.root.$[HOST_NAME] : res.root.$.version ? result.xmlVersion = res.root.$.version : res.root.$.PPRO && (result.xmlVersion = res.root.$.PPRO), UserModel.setUID(res.root.$.id), PLUGIN_VERSION != result.xmlVersion && (console.log("DestinationsService other or no version number in xml, first time user: ", result.xmlVersion), UserModel.setFirstTimeUser(!0)); - var destinations = res.root.destinations[0].destination; - if (console.log("DestinationsService destinations: ", destinations), destinations) { - for (i = 0; i < destinations.length; i++) - 1 == AppModel.baseFolders.indexOf(destinations[i].$.destination) && fs.existsSync(destinations[i].$.destination + path.sep + "pond5") && AppModel.baseFolders.push(destinations[i].$.destination); - fs.stat(AppModel.baseFolders[0] + path.sep + "pond5", function(err, stats) { - err ? setTimeout(function() { - $rootScope.$emit("modal add destination requested") - }, 3e3) : AppModel.currentBaseFolder = AppModel.baseFolders[0] - }), console.log("DestinationsService AppModel.baseFolders : ", AppModel.baseFolders), console.log("DestinationsService currentBaseFolder : ", AppModel.currentBaseFolder) - } - if (UserModel.getFirstTimeUser()) { - var newVersion = HOST_NAME + '="' + PLUGIN_VERSION + '"'; - result.parsedXML.root.$[HOST_NAME] ? result.xml = result.xml.replace(HOST_NAME + '="' + result.xmlVersion + '"', newVersion) : result.parsedXML.root.$.version && "PPRO" === HOST_NAME ? result.xml = result.xml.replace('version="' + result.xmlVersion + '"', newVersion) : result.parsedXML.root.$.version && "PPRO" != HOST_NAME ? result.xml = result.xml.replace('version="' + result.xmlVersion + '"', 'version="' + result.xmlVersion + '" ' + newVersion) : result.parsedXML.root.$.PPRO && !result.parsedXML.root.$[HOST_NAME] && (result.xml = result.xml.replace('PPRO="' + result.xmlVersion + '"', 'PPRO="' + result.xmlVersion + '" ' + newVersion)), console.log("DestinationsService result.xml replaced: ", result.xml), console.log("DestinationsService getFirstTimeUser is true, show intro"), setTimeout(function() { - $rootScope.$emit("intro requested") - }, 3e3) - } - }), parser.parseString(result.xml) - }, - writeToDisk: function() { - fs.writeFile(result.file, result.xml, function(err) { - if (err) throw err; - result.readXML() - }) - } - }; - return result -}]), app.service("ImportService", ["$rootScope", function($rootScope) { - this.importClips = function(items) { - var i, importPaths = []; - for (i = 0; i < items.length; i++) console.log("ImportService item.canceled:", items[i].canceled), items[i].canceled || items[i].imported || (items[i].imported = !0, importPaths.push(items[i].downloadDestination + items[i].fileName)); - console.log("ImportService importPath:", importPaths); - var obj = { - paths: importPaths - }; - csInterface.evalScript("importClips(" + JSON.stringify(obj) + ")", function(result) { - console.log("ImportService result: ", result), $rootScope.$emit("on importing bin complete") - }) - } -}]), app.service("OpenURLService", [function() { - this.openURL = function(url) { - csInterface.openURLInDefaultBrowser(url) - } -}]), app.controller("AdvancedSearchController", function($scope, ViewStateModel, SearchModel, ViewStateService) { - $scope.obj = { - show: !1, - fpsItems: [{ - fps: "23.98" - }, { - fps: "24" - }, { - fps: "25" - }, { - fps: "29.97" - }, { - fps: "30" - }, { - fps: "60" - }, { - fps: "60+" - }], - resItems: [{ - res: "4K+", - param: "8K" - }, { - res: "4K", - param: "4K" - }, { - res: "2K", - param: "2K" - }, { - res: "HD (1080)", - param: "HD1080" - }, { - res: "HD (720)", - param: "HD720" - }, { - res: "SD", - param: "SD" - }, { - res: "Web", - param: "WEB" - }], - showCbFilters: !0, - _minPrice: 0, - _maxPrice: 500, - minPrice: function(newValue) { - return arguments.length ? $scope.obj._minPrice = newValue : $scope.obj._minPrice - }, - maxPrice: function(newValue) { - return 500 == $scope.obj._maxPrice ? $scope.obj.maxPriceValue = "$500+" : $scope.obj.maxPriceValue = "$" + $scope.obj._maxPrice, arguments.length ? $scope.obj._maxPrice = newValue : $scope.obj._maxPrice - }, - _minTime: 0, - _maxTime: 120, - minTime: function(newValue) { - return arguments.length ? $scope.obj._minTime = newValue : $scope.obj._minTime - }, - maxTime: function(newValue) { - return 120 == $scope.obj._maxTime ? $scope.obj.showTimePlusSign = !0 : $scope.obj.showTimePlusSign = !1, arguments.length ? $scope.obj._maxTime = newValue : $scope.obj._maxTime - } - }, $scope.oneAtATime = !0, $scope.reset = function() { - for ($scope.obj._minPrice = 0, $scope.obj._maxPrice = 500, $scope.obj._minTime = 0, $scope.obj._maxTime = 120, SearchModel.fps = "", SearchModel.fpsgt = "", SearchModel.res = "", SearchModel.pricegt = "", SearchModel.pricelt = "", SearchModel.durationgt = "", SearchModel.durationlt = "", i = 0; i < $scope.obj.fpsItems.length; i++) $scope.obj.fpsItems[i].checked = !1; - for (i = 0; i < $scope.obj.resItems.length; i++) $scope.obj.resItems[i].checked = !1 - }, $scope.reset(), $scope.$root.$on("filters button clicked", function(event, state) { - $scope.obj.show = state - }), $scope.$root.$on("media filter change", function(event, data) { - data == BM_VIDEO || data == BM_PUBLIC_DOMAIN ? $scope.obj.showCbFilters = !0 : ($scope.obj.showCbFilters = !1, $scope.reset()), data == BM_AFTER_EFFECTS ? $scope.obj.showDuration = !1 : $scope.obj.showDuration = !0 - }), $scope.change = function() { - var fpsgt, fps = " fps", - res = " resolutions"; - for (i = 0; i < $scope.obj.fpsItems.length - 1; i++) $scope.obj.fpsItems[i].checked && (fps += ":" + $scope.obj.fpsItems[i].fps); - for (fpsgt = $scope.obj.fpsItems[6].checked ? " fpsgt:60" : "", i = 0; i < $scope.obj.resItems.length; i++) $scope.obj.resItems[i].checked && (res += ":" + $scope.obj.resItems[i].param); - fps.length <= 5 ? fps = "" : fpsgt = "", res.length <= 13 && (res = ""), SearchModel.fps = fps, SearchModel.fpsgt = fpsgt, SearchModel.res = res, SearchModel.resultType = "replace", SearchModel.page = 0, ViewStateService.viewRequested("search") - }, $scope.onHideFiltersClicked = function() { - $scope.obj.show = !1, $scope.$root.$emit("filters button clicked", !1) - }, $scope.onResetFiltersClicked = function() { - $scope.reset(), $scope.change() - }, $scope.viewState = function() { - return ViewStateModel.getState() - }, $scope.$watch($scope.viewState, function() { - "cart" !== ViewStateModel.getState() && "downloads" !== ViewStateModel.getState() || ($scope.obj.show = !1) - }, !0), window.addEventListener("rangeSliderOff", function(e) { - "" == $scope.obj._minPrice ? SearchModel.pricegt = "" : SearchModel.pricegt = " pricegt:" + $scope.obj._minPrice, "500" == $scope.obj._maxPrice ? SearchModel.pricelt = "" : SearchModel.pricelt = " pricelt:" + $scope.obj._maxPrice, "" == $scope.obj._minTime ? SearchModel.durationgt = "" : SearchModel.durationgt = " durationgt:" + $scope.obj._minTime, "120" == $scope.obj._maxTime ? SearchModel.durationlt = "" : SearchModel.durationlt = " durationlt:" + $scope.obj._maxTime, $scope.change() - }, !1) -}), app.controller("AlertController", function($scope) { - $scope.alerts = [], $scope.addAlert = function() { - console.log("AlertController add"), $scope.alerts.push({ - msg: "Another alert!" - }) - }, $scope.closeAlert = function(index) { - $scope.alerts.splice(index, 1) - } -}), app.controller("BinsController", function($scope, BinsModel, Service, LoginModel, ViewStateModel, ViewStateService) { - $scope.obj = {}, $scope.obj.showImportAll = !1, $scope.obj.showSelect = !1, $scope.obj.direction = "dropup", $scope.loginModel = function() { - return LoginModel.loggedIn - }, $scope.viewStateModel = function() { - return ViewStateModel.getState() - }, $scope.$watch($scope.loginModel, function() { - LoginModel.loggedIn ? $scope.obj.showSelect = !0 : $scope.obj.showSelect = !1 - }), $scope.$watch($scope.viewStateModel, function() { - "bins" != ViewStateModel.getState() && ($scope.obj.selectedNameFormatted = "Collection") - }), $scope.$root.$on("onBins", function(event) { - $scope.bins = BinsModel.bins - }), $scope.onClick = function() { - console.log("BinsController onClick"), $scope.$root.$emit("select clicked") - }, $scope.onChange = function(bin) { - console.log("onChange, bin: ", bin), 14 < bin.name.length ? $scope.obj.selectedNameFormatted = bin.name.substr(0, 14) + "..." : $scope.obj.selectedNameFormatted = bin.name, $scope.obj.open = !1, $scope.selected = bin, $scope.selected && (BinsModel.selectedBin = bin, $scope.$root.$emit("bin selected", bin.name), ViewStateService.viewRequested("bins")) - }, $scope.onDelete = function(bin) { - console.log("onDelete, bin: ", bin) - }, $scope.toggled = function(open) { - $scope.obj.direction = open ? "down" : "dropup" - }, $scope.onAddClicked = function() { - console.log("onAddClicked"), $scope.$root.$emit("modal add collection requested") - }, $scope.onRemoveClicked = function() { - console.log("onRemoveClicked"), $scope.$root.$emit("modal remove collection requested") - } -}), app.controller("CartController", function($scope, Service, ViewStateService, CartModel, LoginModel, AnalyticsService) { - $scope.obj = { - numberOfItem: 0, - clearCartIcon: CLEAR_CART_TRASH_IMG, - imageUrl: CART_BUTTON_IMG, - cartButtonStyle: "button-cart-logged-out" - }, $scope.cartModel = function() { - return CartModel.cartVO - }, $scope.$watch($scope.cartModel, function() { - CartModel.cartVO.items && ($scope.obj.numberOfItems = CartModel.cartVO.items.length) - }), $scope.loginModel = function() { - return LoginModel - }, $scope.$watch($scope.loginModel, function() { - LoginModel.getLoggedIn() ? $scope.obj.cartButtonStyle = "button-cart-logged-in" : ($scope.obj.cartButtonStyle = "button-cart-logged-out", $scope.obj.numberOfItems = "") - }, !0), $scope.onCartButtonClicked = function() { - ViewStateService.viewRequested("cart"); - var ga = { - ec: "cart" - }; - AnalyticsService.sendData(ga) - } -}), app.controller("CheckOutController", function($scope, Service, ViewStateModel, CheckOutService, CartModel) { - $scope.obj = { - show: !1, - disabled: !0, - info: "", - showInfo: !1, - subTotalText: "", - showVAT: !1, - lineStyle: "", - totalStyle: "", - remainingStyle: "", - cartInfoStyle: "" - }, $scope.CartModel = function() { - return CartModel.cartVO - }, $scope.$watch($scope.CartModel, function() { - CartModel.cartVO.items && 0 < CartModel.cartVO.items.length ? $scope.obj.disabled = !1 : $scope.obj.disabled = !0 - }, !0), $scope.$root.$on("checkout complete", function() { - $scope.obj.disabled = !1 - }), $scope.$root.$on("billing info canceled", function() { - $scope.obj.disabled = !1 - }), $scope.viewState = function() { - return ViewStateModel.getState() - }, $scope.$watch($scope.viewState, function() { - "cart" === ViewStateModel.getState() ? $scope.obj.show = !0 : $scope.obj.show = !1 - }, !0), $scope.onClick = function() { - $scope.obj.disabled = !0, $scope.$root.$emit("on modal choose billing info requested"), $scope.onOut() - }, $scope.onOver = function() { - $scope.obj.showInfo = !0, $scope.showData() - }, $scope.onOut = function() { - $scope.obj.showInfo = !1 - }, $scope.showData = function() { - var data = CartModel.getCartTotal(); - data && ($scope.obj.subTotalText = data.subtotals.beforeDiscounts, data.vatData.display ? $scope.obj.showVAT = !0 : $scope.obj.showVAT = !1, $scope.obj.showVAT ? ($scope.obj.cartInfoStyle = "cart-info-vat", $scope.obj.lineStyle = "cart-info-line-vat", $scope.obj.totalStyle = "cart-info-total-vat", $scope.obj.remainingStyle = "cart-info-remaining-vat", $scope.obj.vatPerc = data.vatData.percentage, $scope.obj.vat = data.vatData.amount) : ($scope.obj.cartInfoStyle = "cart-info-no-vat", $scope.obj.lineStyle = "cart-info-line-no-vat", $scope.obj.totalStyle = "cart-info-total-no-vat", $scope.obj.remainingStyle = "cart-info-remaining-no-vat"), $scope.obj.credits = data.creditsData.usedSum, $scope.obj.total = data.subtotals.final, $scope.obj.remaining = data.creditsData.remainingSum) - }, $scope.$root.$on("alreadyBought", function(event, data) { - CheckOutService.onCheckOutRequested(data) - }), $scope.$root.$on("ownClips", function(event, data) { - CheckOutService.onCheckOutRequested(data) - }) -}), app.controller("CollectionsController", function($scope, BinsModel, Service, LoginModel, ViewStateService) { - $scope.obj = {}, $scope.obj.showImportAll = !1, $scope.obj.showFooter = !1, $scope.obj.showList = !1, $scope.obj.showBin, $scope.obj.addToBin, $scope.obj.addToBinName = "Collections", $scope.obj.collectionsList = COLLECTIONS_LIST_HTML, $scope.loginModel = function() { - return LoginModel.loggedIn - }, $scope.$watch($scope.loginModel, function() { - LoginModel.loggedIn ? $scope.obj.showFooter = !0 : $scope.obj.showFooter = !1 - }), $scope.$root.$on("onBins", function(event) { - $scope.bins = BinsModel.bins, 0 == BinsModel.bins.length && ($scope.obj.addToBinName = "Collections") - }), $scope.$root.$on("active bin changed", function(event) { - $scope.obj.addToBin = BinsModel.addToBin, BinsModel.addToBin && ($scope.obj.addToBinName = getAbbrName(BinsModel.addToBin.name, 10)) - }), $scope.toggleList = function() { - $scope.obj.showList = !$scope.obj.showList - }, $scope.openList = function() { - $scope.obj.showList = !0 - }, $scope.closeList = function() { - $scope.obj.showList = !1 - }, $scope.deleteIconClicked = function(bin) { - $scope.$root.$emit("collection delete requested", [bin]) - }, $scope.showCollectionIconClicked = function(bin) { - BinsModel.showBin = bin, $scope.$root.$emit("bin selected", bin.name), ViewStateService.viewRequested("bins"), $scope.closeList() - }, $scope.collectionNameClicked = function(bin) { - BinsModel.addToBin = bin, $scope.obj.addToBinName = getAbbrName(bin.name, 10), $scope.closeList(), Service.setActiveBin(BinsModel.addToBin.id) - }, $scope.freeItemsClicked = function() { - ViewStateService.viewRequested("freebies"), $scope.closeList() - }, $scope.onClick = function() { - $scope.$root.$emit("select clicked") - }, $scope.onAddClicked = function() { - $scope.$root.$emit("modal add collection requested") - } -}), app.controller("DownloadAllController", function($scope, ViewStateModel, DownloadBatchService, PurchasesModel, AnalyticsService) { - function onStateChange() { - "downloads" === ViewStateModel.getState() && PurchasesModel.purchasesVO && PurchasesModel.purchasesVO.items ? $scope.obj.show = !0 : $scope.obj.show = !1 - } - $scope.obj = { - show: !1, - isDownloading: !1 - }, $scope.$root.$on("on downloading all purchases complete", function(event) { - $scope.$apply(function() { - $scope.obj.isDownloading = !1 - }) - }), $scope.$root.$on("cancel all requested", function(event) { - console.log("DownloadAllController cancel all requested"), $scope.obj.isDownloading = !1 - }), $scope.$root.$on("on purchases vo", function() { - onStateChange() - }), $scope.viewState = function() { - return ViewStateModel.getState() - }, $scope.$watch($scope.viewState, onStateChange, !0), $scope.onDownloadAllClicked = function() { - console.log("DownloadAllController onDownloadAllClicked"), $scope.obj.isDownloading = !0, DownloadBatchService.onBatchRequested(); - var ga = { - ec: "download%20all" - }; - console.log("DownloadAllController ga", ga), AnalyticsService.sendData(ga) - } -}), app.controller("DownloadProgressController", function($scope, $timeout, ProgressService, DownloadRequestService, DownloadCancelService, ViewStateModel, DownloadModel) { - $scope.obj = { - items: [], - isOpen: !1, - progressCloseIcon: PROGRESS_CLOSE_IMG - }, $scope.viewStateModel = function() { - return ViewStateModel.getState() - }, $scope.$watch($scope.viewStateModel, function() { - $scope.obj.view = ViewStateModel.getState() - }), $scope.$root.$on("select clicked", function(event) { - $scope.obj.isOpen = !1 - }), $scope.$root.$on("import all clicked", function(event) { - $scope.obj.isOpen = !0 - }), $scope.$root.$on("open progress", function(event) { - $scope.obj.isOpen || ($scope.obj.isOpen = !0) - }), $scope.$root.$on("clear progress", function(event) { - $scope.obj.items = DownloadModel.itemsDownloadList - }), $scope.$root.$on("added to progress", function(event, data) { - $scope.obj.items = DownloadModel.itemsDownloadList - }), $scope.onProgressIconClicked = function() { - $scope.$root.$emit("progress button clicked") - }, $scope.$root.$on("progress button clicked", function(event) { - $scope.obj.isOpen = !$scope.obj.isOpen - }), $scope.clearListClicked = function() { - $scope.$root.$emit("progress button clicked"), ProgressService.clearCompleteItems(), 0 < $scope.obj.items.length ? $scope.obj.isOpen = !0 : $scope.obj.isOpen = !1 - }, $scope.showClear = function() { - var show = !1; - return $scope.obj.items.forEach(function(item) { - item.completed && (show = !0) - }), !ProgressService.getDownloadingStatus() && 0 < DownloadModel.itemsDownloadList.length && (show = !0), show - }, $scope.isDownloading = function() { - var isDownloading = !1; - return $scope.obj.items.forEach(function(item) { - item.downloading && (isDownloading = !0) - }), ProgressService.getDownloadingStatus() && (show = !0), isDownloading - }, $scope.showMenu = function() { - return 0 < $scope.obj.items.length - }, $scope.cancelAllClicked = function() { - DownloadCancelService.onCancelAll(), $scope.$root.$emit("cancel all requested") - }, $scope.closeClicked = function() { - $scope.$root.$emit("progress button clicked"), console.log("DownloadProgressController closeClicked", $scope.obj.isOpen), $scope.obj.isOpen = !1, console.log("DownloadProgressController closeClicked", $scope.obj.isOpen) - }, $scope.cancelSingleClicked = function(item) { - DownloadCancelService.onCancelSingle(item) - }, $scope.hideTooltip = function() { - $timeout(function() { - $("#clearListButton").trigger("hide") - }, 0) - } -}), app.controller("FilterController", function($scope, Service, SearchModel, ViewStateModel, AnalyticsService) { - $scope.obj = { - filters: ["Best Match", "Popular", "Newest", "Price", "Duration"] - }, $scope.caret = { - direction: "down" - }, $scope.obj.selected = $scope.obj.filters[0], $scope.onChange = function(val) { - var sortID; - switch (console.log("FilterController changed: ", $scope.obj.selected), $scope.obj.selected = val || $scope.obj.selected, $scope.obj.open = !1, $scope.obj.selected) { - case "Best Match": - sortID = 1; - break; - case "ARTIST": - sortID = 2; - break; - case "Newest": - sortID = 6; - break; - case "Duration": - sortID = 5; - break; - case "Popular": - sortID = 8; - break; - case "PAGE VIEWS": - sortID = 10; - break; - case "Price": - sortID = 4 - } - console.log("FilterController sortID: ", sortID), SearchModel.filter = sortID, SearchModel.resultType = "replace", SearchModel.page = "0", Service.search(), window.scrollTo(0, 0); - var ga = {}; - ga.ec = "search%20filter%20" + $scope.obj.selected.replace(/ /g, "%20"), ga.label = SearchModel.query, AnalyticsService.sendData(ga) - }, $scope.setCurrent = function(val) { - $scope.obj.selected = val - }, $scope.toggled = function(open) { - $scope.obj.direction = open ? "dropup" : "down" - } -}), app.controller("FooterLinksController", function($scope, ViewStateModel, CartModel) { - $scope.obj = { - show: !1 - }, $scope.viewState = function() { - return ViewStateModel.getState() - }, $scope.$watch($scope.viewState, function() { - "cart" === ViewStateModel.getState() ? $scope.obj.show = !0 : $scope.obj.show = !1 - }, !0), $scope.onPromoCodeClicked = function() { - $scope.$root.$emit("modal promo requested") - } -}); -var FreebiesController = function($scope, ViewStateService, FreebiesModel, ViewStateModel, LoginModel, AnalyticsService) { - function onViewStateChange() { - console.log("FreebiesController onViewStateChange:", ViewStateModel.getState()), "freebies" === ViewStateModel.getState() && LoginModel.getLoggedIn() ? $scope.obj.show = !0 : $scope.obj.show = !1 - } - $scope.obj = { - show: !1 - }, $scope.viewState = function() { - return ViewStateModel.getState() - }, $scope.loggedIn = function() { - return LoginModel.getLoggedIn() - }, $scope.$watch($scope.viewState, onViewStateChange, !0), $scope.$watch($scope.loggedIn, onViewStateChange), $scope.onFreebiesButtonClicked = function() { - ViewStateService.viewRequested("freebies"), console.log("FreebiesController onFreebiesButtonClicked"); - var ga = { - ec: "freebies" - }; - console.log("FreebiesController ga", ga), AnalyticsService.sendData(ga) - }, $scope.onAddAllFreebiesToCartClicked = function() { - var ids = []; - FreebiesModel.freebiesVO.items.forEach(function(item) { - ids.push(item.id) - }); - var apiObj = { - fn: "modifyCart", - args: [convertArrayToCommaSeperatedString(ids), ""] - }; - $scope.$root.$emit("api call", apiObj), $scope.$root.$emit("modal add to cart") - } -}; -FreebiesController.$inject = ["$scope", "ViewStateService", "FreebiesModel", "ViewStateModel", "LoginModel", "AnalyticsService"], app.controller("ImportCollectionsController", function($scope, DownloadModel, ViewStateModel, BinsModel) { - $scope.obj = { - show: !1, - isImporting: !1 - }, $scope.$root.$on("on importing bin complete", function(event) { - console.log("ImportCollectionsController on importing bin complete"), $scope.$apply(function() { - $scope.obj.isImporting = !1 - }) - }), $scope.viewState = function() { - return ViewStateModel.getState() - }, $scope.binsModel = function() { - return BinsModel.binVO - }, $scope.$watch($scope.viewState, function() { - "bins" === ViewStateModel.getState() ? $scope.obj.show = !0 : $scope.obj.show = !1 - }, !0), $scope.$watch($scope.binsModel, function() { - "bins" === ViewStateModel.getState() && ($scope.obj.show = !0, 0 < BinsModel.binVO.items.length ? $scope.obj.isImporting = !1 : $scope.obj.isImporting = !0) - }, !0), $scope.onImportAllClicked = function() { - $scope.obj.isImporting = !0, $scope.$root.$emit("download requested", BinsModel.binVO.items), $scope.$root.$emit("import all clicked") - } -}), app.controller("IntroAssetsController", function($scope) { - $scope.obj = { - state: 0, - stateName: "" - }, $scope.$root.$on("intro asset requested", function(event, stateObj) { - $scope.obj.stateName = stateObj.stateName, console.log("IntroAssetsController stateName", $scope.obj.stateName); - var fromX, toX, fromY, toY, currArrow = stateObj.arrowClass; - switch (currArrow) { - case ".intro-asset-arrow-up": - fromY = 20, toY = 0; - break; - case ".intro-asset-arrow-left": - fromX = 20, toX = 0; - break; - case ".intro-asset-arrow-down": - fromY = 0, toY = 20 - } - "" != currArrow && ($(currArrow).css("top", "").css("left", "").css("bottom", ""), $(currArrow).css(stateObj.posX[0], stateObj.posX[1]), $(currArrow).css(stateObj.posY[0], stateObj.posY[1]), $(".intro-asset-arrow").velocity("stop"), $scope.loop(currArrow, fromX, toX, fromY, toY)) - }), $scope.loop = function(target, fromX, toX, fromY, toY) { - $(target).velocity({ - translateX: [fromX, toX], - translateY: [fromY, toY] - }, { - duration: 1e3, - loop: !0 - }) - } -}), app.controller("ListItemController", function($scope, VersionsModel, ViewStateModel) { - $scope.obj = {}, $scope.deleteIconClicked = function() { - var apiObj = { - fn: "modifyCart", - args: ["", $scope.item.id] - }; - $scope.$root.$emit("api call", apiObj) - }, $scope.versionButtonClicked = function() { - VersionsModel.setVersions($scope.item.versions) - }, $scope.imageHovered = function(e) { - var item; - "cart" == ViewStateModel.getState() ? item = $scope.item : "downloads" == ViewStateModel.getState() && (item = $scope.item.versions[0]), $scope.$root.$emit("start preview", item) - }, $scope.imageLeft = function(item) { - $scope.$root.$emit("stop preview", item) - } -}), app.controller("ListCartController", function($scope, CartModel) { - $scope.obj = {}, $scope.cartItems = function() { - return CartModel - }, $scope.$watchCollection($scope.cartItems, function() { - CartModel.cartVO && ($scope.obj.items = CartModel.cartVO.items) - }) -}), app.controller("ListDownloadsController", function($scope, PurchasesModel) { - $scope.obj = {}, $scope.purchasedItems = function() { - return PurchasesModel - }, $scope.$watchCollection($scope.purchasedItems, function() { - PurchasesModel.purchasesVO && (console.log("ListController onPurchasesModelChange: ", PurchasesModel.purchasesVO.items), $scope.obj.items = PurchasesModel.purchasesVO.items) - }) -}), app.controller("LoginController", function($scope, LoginModel, UserModel) { - $scope.obj = { - loggedIn: !1, - logo: LOGO_IMG, - logoStyle: "logo-reg" - }, $scope.loginModel = function() { - return LoginModel - }, $scope.userModel = function() { - return UserModel - }, $scope.$watch($scope.loginModel, function() { - void 0 === LoginModel.getLoggedIn() ? $scope.obj.loggedIn = $scope.obj.loggedIn : $scope.obj.loggedIn = LoginModel.getLoggedIn(); - $scope.obj.loggedIn && ($scope.obj.avatarURL = UserModel.getAvatarURL()); - !1 === LoginModel.getLoggedIn() || void 0 === LoginModel.getLoggedIn() ? $scope.obj.row_top_style = "row-top-loggedout" : $scope.obj.row_top_style = "row-top-loggedin" - }, !0), $scope.$watch($scope.userModel, function() { - $scope.obj.avatarURL = UserModel.getAvatarURL(), 0 < THIRD_PARTY.length && ($scope.obj.logo = BASE_URL + "pond5_shared/images/" + THIRD_PARTY + ".png", $scope.obj.logoStyle = "logo-tp") - }, !0), $scope.loginRequested = function() { - $scope.$root.$emit("modal login requested") - }, $scope.logoutClicked = function() { - $scope.$root.$emit("modal logout requested") - } -}), app.controller("MainViewController", function($scope, ViewStateModel, SearchModel) { - $scope.obj = { - tilesClass: "main-content" - }, $scope.$root.$on("filters button clicked", function(event, state) { - $scope.obj.tilesClass = state ? (ViewStateModel.setState("search"), "main-content-advanced-search") : "main-content" - }), $scope.$root.$on("advanced search close requested", function(event) { - $scope.obj.tilesClass = "main-content" - }), $scope.viewState = function() { - return ViewStateModel.getState() - }, $scope.$watch($scope.viewState, function() { - "search" === ViewStateModel.getState() && "add" === SearchModel.resultType ? console.log("MainViewController, do not scroll to top") : window.scrollTo(0, 0); - "cart" !== ViewStateModel.getState() && "downloads" !== ViewStateModel.getState() || ($scope.obj.tilesClass = "main-content"); - $scope.obj.state = ViewStateModel.getState() - }, !0) -}); -var MenuController = function($scope, ViewStateService, AnalyticsService) { - $scope.states = ["default", "hover", "selected"], $scope.btn0 = { - state: $scope.states[2], - selected: !0 - }, $scope.btn1 = { - state: $scope.states[0], - selected: !1 - }, $scope.btn2 = { - state: $scope.states[0], - selected: !1 - }, $scope.btn3 = { - state: $scope.states[0], - selected: !1 - }, $scope.buttons = [$scope.btn0, $scope.btn1, $scope.btn2, $scope.btn3], $scope.click = function(button) { - console.log("MenuController clicked ", button), $scope.selected = button; - for (var i = 0; i < $scope.buttons.length - 1; i++) button === $scope.buttons[i] ? ($scope.buttons[i].selected = !0, $scope.buttons[i].state = $scope.states[2]) : button != $scope.buttons[3] && ($scope.buttons[i].selected = !1, $scope.buttons[i].state = $scope.states[0]); - var view; - switch (button) { - case $scope.buttons[0]: - view = "search"; - break; - case $scope.buttons[1]: - view = "downloads"; - break; - case $scope.buttons[2]: - view = "previews"; - break; - case $scope.buttons[3]: - view = "settings" - } - console.log("MenuController clicked view ", view), $scope.requestView(view) - }, $scope.requestView = function(view) { - "settings" === view ? $scope.$root.$emit("modal add destination requested") : ViewStateService.viewRequested(view); - var ga = {}; - ga.ec = view, console.log("MenuController ga", ga), AnalyticsService.sendData(ga) - }, $scope.over = function(button) { - console.log("MenuController over ", button), button.selected || (button.state = $scope.states[1]) - }, $scope.out = function(button) { - console.log("MenuController over ", button), button.selected || (button.state = $scope.states[0]) - } -}; -MenuController.$inject = ["$scope", "ViewStateService", "AnalyticsService"], app.controller("MessageController", function($scope, ViewStateModel) { - $scope.obj = { - show: !1 - }, $scope.$root.$on("message view requested", function(event, show, data, list, imgUrl) { - $scope.obj.title = null, $scope.obj.messageList = null, $scope.obj.message = null, $scope.obj.imgUrl = null, $scope.obj.showImg = !1, ($scope.obj.show = show) && ($scope.obj.title = data[0], list ? $scope.obj.messageList = data[1] : $scope.obj.message = data[1], 2 === data.length ? $scope.obj.label = "OK" : $scope.obj.label = data[2], imgUrl && ($scope.obj.imgUrl = imgUrl, $scope.obj.showImg = !0)) - }), $scope.viewStateModel = function() { - return ViewStateModel.getState() - }, $scope.$watch($scope.viewStateModel, function() { - "search" !== ViewStateModel.getState() && ($scope.obj.show = !1) - }) -}), app.controller("ModalAddCollectionConfirmationController", function($scope, $uibModal, BinsModel) { - $scope.items = [], $scope.$root.$on("collection created", function(event, data) { - console.log("ModalAddCollectionConfirmationController event handler", data), $scope.open("sm") - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_ADD_COLLECTION_CONFIRMATION_HTML, - controller: ModalAddCollectionConfirmationInstanceCtrl, - size: size, - resolve: { - items: function() { - return $scope - } - } - }).result.then(function() { - console.log("ModalAddCollectionConfirmationController OK") - }, function() { - console.log("ModalAddCollectionConfirmationController CANCELED") - }) - } -}); -var ModalAddCollectionConfirmationInstanceCtrl = function($scope, $uibModalInstance, items, BinsModel) { - $scope.obj = { - title: "Complete!", - messagePre: "Your collection '", - messagePost: "' was succesfully created", - newBinName: BinsModel.newBinName - }, $scope.ok = function() { - $uibModalInstance.dismiss("cancel") - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel") - } -}; -app.controller("ModalAddCollectionController", function($scope, $uibModal, Service, UserModel, BinsModel) { - $scope.items = [], $scope.$root.$on("modal add collection requested", function(event) { - console.log("ModalAddCollectionController event handler"), $scope.open("sm") - }), $scope.open = function(size) { - var modalInstance = $uibModal.open({ - templateUrl: MODAL_ADD_COLLECTION_HTML, - controller: ModalAddCollectionInstanceCtrl, - size: size, - windowClass: "modal-small", - resolve: { - items: function() { - return $scope - } - } - }); - modalInstance.result.then(function() { - console.log("ModalAddCollectionController OK") - }, function() { - console.log("ModalAddCollectionController CANCELED") - }), modalInstance.result.then(function(result) {}, function(result) {}) - } -}); -var ModalAddCollectionInstanceCtrl = function($scope, $uibModalInstance, items, Service, BinsModel) { - $scope.obj = { - showMessage: !1 - }, $scope.create = function() { - console.log("ModalAddCollectionInstanceCtrl bin name: ", document.getElementById("addCollectionInput").value); - var binName = document.getElementById("addCollectionInput").value; - 1 < binName.length && ($uibModalInstance.close(), BinsModel.newBinName = binName, Service.createBin(binName)) - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel") - } -}; -app.controller("ModalAddToCartController", function($scope, $uibModal, Service, ViewStateService) { - $scope.$root.$on("modal add to cart", function(event) { - console.log("ModalAddToCartController event handler"), $scope.open("sm") - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_ADD_TO_CART_HTML, - controller: ModalAddToCartInstanceCtrl, - size: size - }).result.then(function() { - console.log("ModalAddToCartController proceed"), ViewStateService.viewRequested("cart") - }, function() { - console.log("ModalAddToCartController later") - }) - } -}); -var ModalAddToCartInstanceCtrl = function($scope, $uibModalInstance) { - $scope.onProceed = function() { - console.log("ModalAddToCartInstanceCtrl onProceed"), $uibModalInstance.close() - }, $scope.onCancel = function() { - $uibModalInstance.dismiss("cancel") - } -}; -app.controller("ModalBillingAddressController", function($scope, $uibModal) { - $scope.obj = {}, $scope.$root.$on("modal billing address requested", function(event) { - console.log("ModalBillingAddressController event handler"), $scope.open("lg") - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_BILLING_ADDRESS_HTML, - controller: ModalBillingAddressInstanceCtrl, - size: size, - windowClass: "modal-billing-address", - resolve: { - obj: function() { - return $scope.obj - } - } - }).result.then(function() { - console.log("ModalBillingAddressController OK") - }, function() { - console.log("ModalBillingAddressController CANCELED"), $scope.$root.$emit("billing info canceled") - }) - } -}); -var ModalBillingAddressInstanceCtrl = function($scope, $uibModalInstance, obj, Service) { - $scope.firstName = "", $scope.lastName = "", $scope.street1 = "", $scope.street2 = "", $scope.province = "", $scope.zipCode = "", $scope.city = "", $scope.state = "", $scope.country = "", $scope.error = !1, $scope.countries = COUNTRIES, $scope.states = STATES, $scope.submit = function(myForm) { - if (console.log("ModalBillingAddressInstanceCtrl ok: ", myForm.firstName.$modelValue, myForm.lastName.$modelValue), console.log("ModalBillingAddressInstanceCtrl form valid: ", myForm.$valid), myForm.$valid) { - var stateCode; - stateCode = "" == myForm.state.$modelValue ? "" : myForm.state.$modelValue.code; - var data = { - country: myForm.country.$modelValue.code, - firstName: myForm.firstName.$modelValue, - lastName: myForm.lastName.$modelValue, - organization: myForm.organization.$modelValue, - department: myForm.department.$modelValue, - companyID: myForm.companyID.$modelValue, - vatID: myForm.vatID.$modelValue, - street1: myForm.street1.$modelValue, - street2: myForm.street2.$modelValue, - province: myForm.province.$modelValue, - zipCode: myForm.zipCode.$modelValue, - city: myForm.city.$modelValue, - state: stateCode - }; - console.log("ModalBillingAddressInstanceCtrl DATA", data); - var apiObj = { - fn: "setBillingAddress", - args: [data] - }; - $scope.$root.$emit("api call", apiObj), $uibModalInstance.dismiss() - } else console.log("ModalBillingAddressInstanceCtrl form is not valid"), $scope.error = !0 - }, $scope.close = function() { - $uibModalInstance.dismiss() - }, $scope.back = function() { - $uibModalInstance.dismiss(), $scope.$root.$emit("on modal choose billing info requested") - } -}; -app.controller("ModalBuyCreditsController", function($scope, $uibModal, ViewStateModel) { - $scope.obj = {}, $scope.$root.$on("modal buy credits requested", function() { - console.log("ModalBuyCreditsController event handler"), $scope.obj.title = "", $scope.obj.message = "As a reminder, only credits purchased in $USD can be used in this Add-on."; - $scope.open("sm") - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_BUY_CREDITS_HTML, - controller: ModalBuyCreditsInstanceCtrl, - size: size, - resolve: { - obj: function() { - return $scope.obj - } - }, - windowClass: "modal-small" - }).result.then(function() { - console.log("ModalBuyCreditsController OK"), ViewStateModel.allowPreviews = !0, opn("https://www.pond5.com/credit-packages") - }, function() { - console.log("ModalBuyCreditsController CANCELED") - }) - } -}); -var ModalBuyCreditsInstanceCtrl = function($scope, $uibModalInstance, obj) { - $scope.obj = {}, $scope.obj.message = obj.message, $scope.obj.title = obj.title, $scope.ok = function() { - console.log("ModalBuyCreditsInstanceCtrl OK"), $uibModalInstance.close() - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel"), console.log("ModalBuyCreditsInstanceCtrl cancel") - } -}; -app.controller("ModalChooseBillingInfoController", function($scope, $uibModal, BillingInfoModel, CheckOutService, Service) { - $scope.items = [], $scope.obj = {}, $scope.$root.$on("on modal choose billing info requested", function(event) { - console.log("ModalChooseBillingInfoController event handler: ", BillingInfoModel.getBillingInfo()), $scope.items = BillingInfoModel.getBillingInfo(), $scope.open("lg") - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_CHOOSE_BILLING_INFO_HTML, - controller: ModalChooseBillingInfoInstanceCtrl, - windowClass: "modal-choose-billing", - size: size, - resolve: { - items: function() { - return $scope.items - } - } - }).result.then(function(item) { - console.log("ModalChooseBillingInfoController ok, selected: ", item.addressid), CheckOutService.onCheckOutRequested() - }, function() { - console.log("ModalChooseBillingInfoController dismissed"), $scope.$root.$emit("billing info canceled") - }) - } -}); -var ModalChooseBillingInfoInstanceCtrl = function($scope, $uibModalInstance, items, BillingInfoModel, Service) { - console.log("ModalChooseBillingInfoInstanceCtrl items", items), console.log("ModalChooseBillingInfoInstanceCtrl default", BillingInfoModel.getDefaultInfo()), $scope.items = items, $scope.selected = BillingInfoModel.getDefaultInfo(), $scope.adyenEncryption = "https://plugin.pond5.com/pond5_shared/images/adyen-encryption.png", $scope.onRbClicked = function(item) { - $scope.selected = item, console.log("ModalChooseBillingInfoInstanceCtrl rb > default", item), BillingInfoModel.setDefaultInfo(item), Service.getCartTotal() - }, $scope.onOKClicked = function() { - $uibModalInstance.close($scope.selected) - }, $scope.close = function() { - $uibModalInstance.dismiss() - }, $scope.addNewClicked = function() { - $uibModalInstance.dismiss(), $scope.$root.$emit("modal billing address requested") - }, $scope.readAgreement = function() { - console.log("ModalChooseBillingInfoInstanceCtrl readAgreement"), opn("https://www.pond5.com/legal/license") - }, $scope.helpCenter = function() { - opn("https://help.pond5.com/hc/en-us/") - }, $scope.callUs = function() { - opn("https://help.pond5.com/hc/en-us/requests/new") - } -}; -app.controller("ModalChooseFormatController", function($scope, $uibModal) { - $scope.items = [], $scope.$root.$on("on add to cart clicked", function(event, formats) { - console.log("ModalChooseFormatController handler, formats: ", formats), $scope.items = [], $scope.items = formats, $scope.open("sm") - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_CHOOSE_FORMAT_HTML, - controller: ModalChooseFormatInstanceCtrl, - size: size, - windowClass: "modal-small", - resolve: { - items: function() { - return $scope.items - } - } - }).result.then(function() {}, function() { - console.log("ModalChooseFormatController dismissed") - }) - } -}); -var ModalChooseFormatInstanceCtrl = function($scope, $uibModalInstance, items, Service) { - $scope.items = items, $scope.items[0].selected = !0, $scope.onRbClicked = function(item, index) { - console.log("ModalChooseFormatInstanceCtrl onRbClicked: " + item + "-" + index); - for (var i = 0; i < $scope.items.length; i++) $scope.items[i].selected = index === i - }, $scope.onAddToCartClicked = function() { - for (var i = 0; i < $scope.items.length; i++) - if ($scope.items[i].selected) { - var item = $scope.items[i], - apiObj = { - fn: "modifyCart", - args: [item.id + ":" + item.offset] - }; - $scope.$root.$emit("api call", apiObj) - } $uibModalInstance.dismiss() - } -}; -app.controller("ModalChooseVersionController", function($scope, $uibModal, Service, DownloadModel) { - $scope.items = [], $scope.$root.$on("on versions selected", function(event, versions) { - console.log("ModalChooseVersionController event handler: ", $scope.items, versions), $scope.items = [], $scope.items = versions, $scope.open("sm") - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_CHOOSE_VERSION_HTML, - controller: ModalChooseVersionInstanceCtrl, - size: size, - resolve: { - items: function() { - return $scope.items - } - }, - windowClass: "modal-small" - }).result.then(function(selectedIndex) { - var selectedItem = $scope.items[selectedIndex]; - DownloadModel.selectedVersion = selectedIndex, Service.getPurchaseURL(selectedItem.id, selectedItem.transactionID, selectedItem.versionID, selectedItem.version) - }, function() { - console.log("ModalChooseVersionController dismissed") - }) - } -}); -var ModalChooseVersionInstanceCtrl = function($scope, $uibModalInstance, items) { - $scope.items = items, $scope.selected = $scope.items[0], $scope.selectedIndex = 0, $scope.onRbClicked = function(index) { - $scope.selected = $scope.items[index], $scope.selectedIndex = index - }, $scope.ok = function() { - $uibModalInstance.close($scope.selectedIndex) - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel") - } -}; -app.controller("ModalClearCartConfirmationController", function($scope, $uibModal) { - $scope.obj = [], $scope.$root.$on("clear cart requested", function(event, data, size) { - console.log("ModalClearCartConfirmationController event handler", data), $scope.obj.title = "Clear My Cart", $scope.obj.message = "Are you sure you want to clear your cart?", $scope.obj.itemsToDelete = data[0], $scope.obj.label = "CLEAR", $scope.obj.showButtonLeft = !0, $scope.obj.labelLeft = "CANCEL", size = size || "sm", $scope.open(size) - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_SIMPLE_HTML, - controller: ModalClearCartConfirmationInstanceCtrl, - size: size, - windowClass: "modal-small", - resolve: { - obj: function() { - return $scope.obj - } - } - }).result.then(function() { - console.log("ModalClearCartConfirmationController OK"); - var apiObj = { - fn: "modifyCart", - args: ["", $scope.obj.itemsToDelete] - }; - $scope.$root.$emit("api call", apiObj) - }, function() { - console.log("ModalClearCartConfirmationController CANCELED") - }) - } -}); -var ModalClearCartConfirmationInstanceCtrl = function($scope, $uibModalInstance, obj) { - $scope.obj = {}, $scope.obj.message = obj.message, $scope.obj.title = obj.title, $scope.obj.label = obj.label, $scope.obj.showButtonLeft = !0, $scope.obj.labelLeft = "CANCEL", $scope.ok = function() { - $uibModalInstance.close() - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel") - } -}; -app.controller("ModalDeleteCollectionConfirmationController", function($scope, $uibModal, Service, ViewStateModel, BinsModel, ViewStateService) { - $scope.obj = {}, $scope.$root.$on("collection delete requested", function(event, data, size) { - console.log("ModalDeleteCollectionConfirmationController event handler", data, data.length, size), $scope.obj.title = "Delete Collection", $scope.obj.message = "Are you sure you want to delete the collection " + data[0].name + "?", $scope.obj.bin = data[0], $scope.obj.label = "DELETE", $scope.obj.showButtonLeft = !0, $scope.obj.labelLeft = "CANCEL", size = size || "sm", $scope.open(size) - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_SIMPLE_HTML, - controller: ModalDeleteCollectionConfirmationInstanceCtrl, - size: size, - windowClass: "modal-small", - resolve: { - obj: function() { - return $scope.obj - } - } - }).result.then(function() { - BinsModel.selectedBin == $scope.obj.bin && ViewStateService.viewRequested("search"), Service.removeBin($scope.obj.bin.id), ViewStateModel.allowPreviews = !0 - }, function() {}) - } -}); -var ModalDeleteCollectionConfirmationInstanceCtrl = function($scope, $uibModalInstance, obj) { - $scope.obj = {}, $scope.obj.message = obj.message, $scope.obj.title = obj.title, $scope.obj.label = obj.label, $scope.obj.showButtonLeft = !0, $scope.obj.labelLeft = "CANCEL", $scope.ok = function() { - $uibModalInstance.close() - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel") - } -}; -app.controller("ModalFreebiesController", function($scope, $uibModal, ViewStateService) { - $scope.$root.$on("modal freebies", function(event) { - console.log("ModalFreebiesController event handler"), $scope.open("lg") - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_FREEBIES_HTML, - controller: ModalFreebiesInstanceCtrl, - size: size - }).result.then(function() { - console.log("ModalFreebiesController OK"), ViewStateService.viewRequested("freebies") - }, function() { - console.log("ModalFreebiesController dismissed") - }) - } -}); -var ModalFreebiesInstanceCtrl = function($scope, $uibModalInstance) { - $scope.ok = function() { - $uibModalInstance.close() - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel") - } -}; -app.controller("ModalLoginController", function($scope, $uibModal) { - $scope.obj = {}, $scope.$root.$on("modal login requested", function(event) { - console.log("ModalLoginController event handler"), $scope.open("lg") - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_LOGIN_HTML, - controller: ModalLoginInstanceCtrl, - size: size, - windowClass: "modal-small", - resolve: { - obj: function() { - return $scope.obj - } - } - }).result.then(function() { - console.log("ModalLoginController OK") - }, function() { - console.log("ModalLoginController CANCELED") - }) - } -}); -var ModalLoginInstanceCtrl = function($scope, $uibModalInstance, obj) { - $scope.obj = {}, $scope.obj.userName = obj.userName, $scope.obj.password = obj.password, $scope.obj.showTitle = !0, $scope.obj.showClose = !0, $scope.loginRequested = function() { - $uibModalInstance.close(); - var apiObj = { - fn: "login", - args: [$scope.obj.userName, $scope.obj.password] - }; - $scope.$root.$emit("api call", apiObj) - }, $scope.close = function() { - $uibModalInstance.dismiss("cancel") - }, $scope.signUp = function() { - opn("https://www.pond5.com/login") - } -}; -app.controller("ModalLogoutConfirmationController", function($scope, $uibModal, Service, ViewStateModel) { - $scope.obj = {}, $scope.$root.$on("modal logout requested", function(event, data, size) { - console.log("ModalLogoutConfirmationController event handler"), $scope.obj.title = "Log out", $scope.obj.message = "Are you sure you want to log out?", $scope.obj.label = "YES", $scope.obj.showButtonLeft = !0, $scope.obj.labelLeft = "CANCEL", size = size || "sm", $scope.open(size) - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_SIMPLE_HTML, - controller: ModalLogoutConfirmationInstanceCtrl, - size: size, - windowClass: "modal-small", - resolve: { - obj: function() { - return $scope.obj - } - } - }).result.then(function() { - Service.logout(), ViewStateModel.allowPreviews = !0 - }, function() {}) - } -}); -var ModalLogoutConfirmationInstanceCtrl = function($scope, $uibModalInstance, obj) { - $scope.obj = {}, $scope.obj.message = obj.message, $scope.obj.title = obj.title, $scope.obj.label = obj.label, $scope.obj.showButtonLeft = !0, $scope.obj.labelLeft = "CANCEL", $scope.ok = function() { - $uibModalInstance.close() - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel") - } -}; -app.controller("ModalNotLoggedInController", function($scope, $uibModal) { - $scope.obj = {}, $scope.$root.$on("modal not logged in", function(event, data) { - $scope.obj.title = data[0], $scope.obj.message = "You're not logged in", $scope.open("lg") - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_NOT_LOGGED_IN_HTML, - controller: ModalNotLoggedInInstanceCtrl, - size: size, - windowClass: "modal-small", - resolve: { - obj: function() { - return $scope.obj - } - } - }).result.then(function() { - console.log("ModalNotLoggedInController OK") - }, function() { - console.log("ModalNotLoggedInController CANCELED") - }) - } -}); -var ModalNotLoggedInInstanceCtrl = function($scope, $uibModalInstance, obj) { - $scope.obj = {}, $scope.obj.message = obj.message, $scope.obj.title = obj.title, $scope.loginRequested = function() { - $uibModalInstance.dismiss("cancel"), $scope.$root.$emit("modal login requested") - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel") - }, $scope.signUp = function() { - opn("https://www.pond5.com/login") - } -}; -app.controller("ModalPromoCodeController", function($scope, $uibModal, Service, UserModel) { - $scope.items = [], $scope.obj = { - label: "APPLY", - onlyNumbers: /^\d+$/ - }, $scope.$root.$on("modal promo requested", function(event) { - console.log("ModalPromoCodeController event handler"), $scope.open("sm") - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_PROMO_CODE_HTML, - controller: ModalPromoCodeInstanceCtrl, - size: size, - windowClass: "modal-small", - resolve: { - items: function() { - return $scope - } - } - }).result.then(function() { - console.log("ModalPromoCodeController OK") - }, function() { - console.log("ModalPromoCodeController CANCELED") - }) - } -}); -var ModalPromoCodeInstanceCtrl = function($scope, $uibModalInstance, items, Service, $filter) { - $scope.obj = { - showMessage: !1, - label: "APPLY", - onlyNumbers: /^\d+$/ - }, $scope.$root.$on("promo code added", function(event, data) { - var message; - console.log("ModalPromoCodeController event handler", data), message = data.commands[0].sum ? $filter("currency")(data.commands[0].sum) + " were succesfully added to your account!" : "Invalid code. Please try again or contact Pond5.", $scope.obj.credits = data, $scope.obj.showMessage = !0, $scope.obj.message = message, $scope.obj.label = "OK" - }), $scope.codeApplied = function() { - if (console.log("ModalPromoCodeInstanceCtrl codeApplied: ", document.getElementById("promoInput").value), "OK" == $scope.obj.label) $uibModalInstance.close(); - else { - var code = document.getElementById("promoInput").value; - 1 < code.length && Service.promoRedeem(code) - } - }, $scope.ok = function() { - console.log("ModalPromoCodeInstanceCtrl OK"), $uibModalInstance.close() - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel") - } -}; -app.controller("ModalRemoveCollectionController", function($scope, $uibModal, Service, BinsModel, ViewStateModel) { - $scope.items = [], $scope.showModal = function() { - return BinsModel.showModal - }, $scope.$root.$on("modal remove collection requested", function(event) { - console.log("ModalRemoveCollectionController remove collection requested event handler", BinsModel.showModal, BinsModel.clipClicked), $scope.items = BinsModel.bins, 0 < $scope.items.length && $scope.open() - }), $scope.$root.$on("collection removed", function(event) { - console.log("ModalAddCollectionController collection removed event handler") - }), $scope.open = function(size) { - var modalInstance = $uibModal.open({ - templateUrl: MODAL_REMOVE_COLLECTION_HTML, - controller: ModalRemoveCollectionInstanceCtrl, - windowClass: "modal-fit", - resolve: { - items: function() { - return $scope.items - } - } - }); - $scope.resetBins = function() { - BinsModel.showModal = !1; - for (var i = 0; i < $scope.items.length; i++) $scope.items[i].selected = !1 - }, modalInstance.result.then(function() { - console.log("OK: ", BinsModel.clipClicked, $scope.items); - for (var i = 0; i < $scope.items.length; i++) $scope.items[i].selected && (console.log("ModalRemoveCollectionController selected bin:", $scope.items[i].id), Service.removeBin($scope.items[i].id)); - $scope.resetBins(), ViewStateModel.allowPreviews = !0 - }, function() { - $scope.resetBins() - }) - } -}); -var ModalRemoveCollectionInstanceCtrl = function($scope, $uibModalInstance, items) { - $scope.items = items, $scope.ok = function() { - $uibModalInstance.close() - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel") - } -}; -app.controller("ModalReplaceController", function($scope, $uibModal, ReplaceModel, ReplaceServiceShared) { - $scope.items = [], $scope.$root.$on("modal replace", function(event, items) { - console.log("ModalReplaceController event handler: ", items), $scope.items = items, $scope.open("lg") - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_REPLACE_HTML, - controller: ModalReplaceInstanceCtrl, - size: size, - resolve: { - items: function() { - return $scope.items - } - }, - windowClass: "modal-replace" - }).result.then(function() { - ReplaceServiceShared.onModalReplaceOK() - }, function() { - ReplaceModel.setState(DEFAULT) - }) - } -}); -var ModalReplaceInstanceCtrl = function($scope, $uibModalInstance, items) { - $scope.obj = { - checkIcon: "https://plugin.pond5.com/pond5_shared/images/check-icon.png", - modalHeader: MODAL_REPLACE_HEADER, - modalContent: MODAL_REPLACE_CONTENT, - resTitle: MODAL_REPLACE_RES_TITLE - }, $scope.items = items; - for (var i = 0; i < $scope.items.length; i++) { - $scope.items[i].selected = !0; - for (var j = 0; j < $scope.items[i].formats.length; j++) console.log("ModalReplaceInstanceCtrl incart: ", $scope.items[i].formats[j].inDownloads), $scope.items[i].formats[j].inDownloads && ($scope.items[i].formats.length = 0), 0 < $scope.items[i].formats.length && $scope.items[i].formats[j].inCart && ($scope.items[i].formats[j].selected = !0, $scope.items[i].oneFormatInCart = !0); - !$scope.items[i].oneFormatInCart && 0 < $scope.items[i].formats.length && ($scope.items[i].formats[0].selected = !0) - } - $scope.selectAllClicked = function() { - var item; - console.log("ModalReplaceInstanceCtrl selectAllClicked: ", $scope.obj.selectAll); - for (var i = 0; i < $scope.items.length; i++) item = $scope.items[i], !$scope.obj.selectAll || item.inCart || item.inDownloads ? item.selected = !0 : item.selected = !1 - }, $scope.onRbClicked = function(item, index) { - console.log("ModalReplaceInstanceCtrl onRbClicked: " + item.name + "-" + item.selected); - for (var i = 0; i < item.formats.length; i++) item.formats[i].selected = index === i - }, $scope.onCbClicked = function(item, index) { - console.log("ModalReplaceInstanceCtrl onCbClicked: " + item.name + "-" + item.selected), item.selected = !item.selected; - for (var i = 0; i < item.formats.length; i++) item.formats[i].selected = index === i; - console.log("ModalReplaceInstanceCtrl onCbClicked after toggle: " + item.name + "-" + item.selected) - }, $scope.ok = function() { - $uibModalInstance.close() - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel") - } -}; -app.controller("ModalReplaceWarningController", function($scope, $uibModal, Service, DownloadModel, ViewStateService, ReplaceModel) { - $scope.obj = {}, $scope.obj.requestedState = "", $scope.$root.$on("modal replace warning", function(event, viewState) { - console.log("ModalReplaceWarningController event handler, event: ", event), console.log("ModalReplaceWarningController event handler, viewState: ", viewState), $scope.obj.requestedState = viewState, $scope.obj.message = "Visiting the " + viewState + " view will cancel the process of replacing your lo-res previews with hi-res clips. Are you sure you want to visit the " + viewState + " view?", $scope.open("sm") - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_REPLACE_WARNING_HTML, - controller: ModalReplaceWarningInstanceCtrl, - size: size, - resolve: { - obj: function() { - return $scope.obj - } - }, - windowClass: "modal-small" - }).result.then(function() { - ViewStateService.onViewApproved(!0) - }, function() { - console.log("ModalReplaceWarningController CANCELED"), ViewStateService.onViewApproved(!1) - }) - } -}); -var ModalReplaceWarningInstanceCtrl = function($scope, $uibModalInstance, obj) { - $scope.obj = {}, $scope.obj.message = obj.message, $scope.ok = function() { - $uibModalInstance.close() - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel") - } -}; -app.controller("ModalSimpleController", function($scope, $uibModal, Service, DownloadModel, ViewStateModel) { - $scope.obj = { - imgUrl: "", - showImg: !1 - }, $scope.$root.$on("modal simple requested", function(event, data, size, list, imgUrl) { - var windowClass; - $scope.obj.title = null, $scope.obj.messageList = null, $scope.obj.message = null, $scope.obj.imgUrl = null, $scope.obj.showImg = !1, list ? $scope.obj.messageList = data[1] : $scope.obj.message = data[1], 2 === data.length ? $scope.obj.label = "OK" : $scope.obj.label = data[2], imgUrl && ($scope.obj.imgUrl = imgUrl, $scope.obj.showImg = !0), "sm" === size ? windowClass = "modal-small" : "lg" === size && (windowClass = "modal-large"), $scope.open(windowClass) - }), $scope.open = function(size) { - $uibModal.open({ - templateUrl: MODAL_SIMPLE_HTML, - controller: ModalSimpleInstanceCtrl, - windowClass: size, - resolve: { - obj: function() { - return $scope.obj - } - } - }).result.then(function() { - ViewStateModel.allowPreviews = !0 - }, function() {}) - } -}); -var ModalSimpleInstanceCtrl = function($scope, $uibModalInstance, obj) { - $scope.obj = {}, $scope.obj.message = obj.message, $scope.obj.messageList = obj.messageList, $scope.obj.title = obj.title, $scope.obj.label = obj.label, $scope.obj.imgUrl = obj.imgUrl, $scope.ok = function() { - $uibModalInstance.close() - }, $scope.cancel = function() { - $uibModalInstance.dismiss("cancel") - } -}; -app.controller("PreviewAudioController", function($scope, ViewStateModel) { - $scope.obj = { - show: !1 - }, $scope.$root.$on("start preview", function(event, item, xpos) { - if (("Music" == item.type || "Sound effect" == item.type) && ViewStateModel.allowPreviews) { - var num = Number(item.dur), - seconds = Math.floor(num / 1e3), - minutes = Math.floor(seconds / 60); - 1 === (seconds = seconds - 60 * minutes).toString().length && (seconds = "0" + seconds); - var format = minutes + ":" + seconds; - $scope.obj.dur = format, item.dur || ($scope.obj.dur = ""), $scope.obj.timer = setTimeout(function() { - document.getElementById("tracktime").style.left = "0px", $scope.playAudio(item.m4aURL, xpos), $scope.obj.name = item.abbrName, item.artistName ? $scope.obj.artist = "BY " + item.artistName.toUpperCase() : "n/a" === item.fps ? $scope.obj.artist = "" : $scope.obj.artist = item.fps, $scope.obj.iconLargeURL = item.iconLargeURL, item.priceRange && item.priceRange[0] != item.priceRange[1] ? ($scope.obj.price = "$" + item.priceRange[0] + "-$" + item.priceRange[1], $scope.obj.priceStyle = "preview-price-double") : ($scope.obj.price = "$" + item.price, $scope.obj.priceStyle = "preview-price-single"), $scope.$apply(function() { - $scope.obj.show = !0 - }) - }, 400) - } - }), $scope.$root.$on("stop preview", function(event, data) { - data && (clearTimeout($scope.obj.timer), setTimeout(function() { - $scope.playAudio("") - }, 200), $scope.obj.name = "", $scope.obj.price = "", $scope.obj.type = "", $scope.obj.dur = "", $scope.obj.show = !1) - }), $scope.playAudio = function(url, xpos) { - var audio = document.getElementById("audio"); - document.getElementById("source-audio").setAttribute("src", url), audio.load() - } -}), app.controller("PreviewPhotoController", function($scope, ViewStateModel) { - $scope.obj = { - show: !1, - showInfo: !0 - }, $scope.$root.$on("start preview", function(event, item, xpos) { - "Photo" != item.type && "Illustration" != item.type || ViewStateModel.allowPreviews && ($scope.obj.timer = setTimeout(function() { - $scope.obj.name = item.abbrName, item.artistName ? $scope.obj.artist = "BY " + item.artistName.toUpperCase() : "n/a" === item.fps ? $scope.obj.artist = "" : $scope.obj.artist = item.fps, $scope.obj.vs = item.vs, $scope.obj.ar = item.ar, $scope.obj.audioCodec = item.audioCodec, $scope.obj.videoCodec = item.videoCodec, item.priceRange && item.priceRange[0] != item.priceRange[1] ? ($scope.obj.price = "$" + item.priceRange[0] + "-$" + item.priceRange[1], $scope.obj.priceStyle = "preview-price-double") : ($scope.obj.price = "$" + item.price, $scope.obj.priceStyle = "preview-price-single"), item.ox ? $scope.obj.res = item.ox + " x " + item.oy : $scope.obj.res = "", $scope.obj.type = item.type, $scope.obj.iconLargeURL = item.iconLargeURL; - var size = convertAspectRatio(370, 208, item.aq); - actualRatio = item.aq, targetRatio = size.x / size.y, adjustmentRatio = targetRatio / actualRatio; - var photo = document.getElementById("photo"); - photo.width = size.x, photo.height = size.y, document.getElementById("preview-loading").style.visibility = "hidden", photo.style.position = "absolute"; - var x_pos = 185 - photo.width / 2; - photo.style.left = x_pos + "px", $scope.obj.name = item.abbrName, item.artistName ? $scope.obj.artist = "BY " + item.artistName.toUpperCase() : "n/a" === item.fps ? $scope.obj.artist = "" : $scope.obj.artist = item.fps, $scope.obj.fps = item.fps, $scope.obj.vs = item.vs, $scope.obj.ar = item.ar, $scope.obj.audioCodec = item.audioCodec, $scope.obj.videoCodec = item.videoCodec, item.videoCodec && -1 != item.videoCodec.indexOf("Apple ProRes") && ($scope.obj.videoCodec = "Apple ProRes"), item.priceRange && item.priceRange[0] != item.priceRange[1] ? ($scope.obj.price = "$" + item.priceRange[0] + "-$" + item.priceRange[1], $scope.obj.priceStyle = "preview-price-double") : ($scope.obj.price = "$" + item.price, $scope.obj.priceStyle = "preview-price-single"), item.ox ? $scope.obj.res = item.ox + " x " + item.oy : $scope.obj.res = "", $scope.$apply(function() { - $scope.obj.show = !0 - }) - }, 400)) - }), $scope.$root.$on("stop preview", function(event, item) { - item && (clearTimeout($scope.obj.timer), $scope.obj.name = "", $scope.obj.price = "", $scope.obj.type = "", $scope.obj.show = !1) - }) -}), app.controller("PreviewVideoController", function($scope, ViewStateModel) { - $scope.obj = { - show: !1, - timer: null, - item: null, - showInfo: !0 - }, $scope.$root.$on("start preview", function(event, item) { - "Video" != item.type && "AE" != item.type || ViewStateModel.allowPreviews && ($scope.obj.timer = setTimeout(function() { - $scope.obj.name = item.abbrName, item.artistName ? $scope.obj.artist = "BY " + item.artistName.toUpperCase() : "n/a" === item.fps && ($scope.obj.artist = ""), $scope.obj.fps = item.fps, $scope.obj.vs = item.vs, $scope.obj.ar = item.ar, $scope.obj.audioCodec = item.audioCodec, $scope.obj.videoCodec = item.videoCodec, item.videoCodec && -1 != item.videoCodec.indexOf("Apple ProRes") && ($scope.obj.videoCodec = "Apple ProRes"), item.priceRange && item.priceRange[0] != item.priceRange[1] ? ($scope.obj.price = "$" + item.priceRange[0] + "-$" + item.priceRange[1], $scope.obj.priceStyle = "preview-price-double") : ($scope.obj.price = "$" + item.price, $scope.obj.priceStyle = "preview-price-single"), item.ox ? $scope.obj.res = item.ox + " x " + item.oy : $scope.obj.res = "", $scope.$apply(function() { - $scope.obj.show = !0 - }), $scope.playVideo(item) - }, 400)) - }), $scope.$root.$on("stop preview", function(event, data) { - clearTimeout($scope.obj.timer), $("#video-frame").children().filter("video").each(function() { - this.pause(), $(this).remove() - }), $("#video-frame").empty(), $scope.obj.name = "", $scope.obj.price = "", $scope.obj.fps = "", $scope.obj.vs = "", $scope.obj.show = !1, document.getElementById("preview-loading").style.visibility = "visible" - }), $scope.playVideo = function(item) { - $("#video-frame").append($("")); - var video = document.getElementsByTagName("video")[0], - source = document.getElementById("source-video"); - video.style.visibility = "hidden"; - var size = convertAspectRatio(370, 208, item.aq); - video.addEventListener("loadedmetadata", function(event) { - video.width = size.x, video.height = size.y, document.getElementById("preview-loading").style.visibility = "hidden", video.style.visibility = "visible" - }), item.h264URL ? (video.pause(), source.setAttribute("src", ""), source.setAttribute("src", item.h264URL), video.load()) : (source.setAttribute("src", ""), video.pause()) - }, $scope.$root.$on("preview info icon over", function() { - $scope.obj.showInfo = !0 - }), $scope.$root.$on("preview info icon out", function() { - $scope.obj.showInfo = !1 - }) -}), app.controller("ReplaceController", function($scope, $timeout, ViewStateModel, ReplaceService, LoginModel, AnalyticsService, ReadClipsOnFSService) { - $scope.obj = { - show: !1, - disabled: !1, - buttonLabel: BUTTON_REPLACE_LABEL, - buttonTooltip: BUTTON_REPLACE_TOOLTIP - }, $scope.$root.$on("replacing complete", function() { - $scope.obj.disabled = !1 - }), $scope.viewState = function() { - return ViewStateModel.getState() - }, $scope.$watch($scope.viewState, function() { - "cart" != ViewStateModel.getState() ? $scope.obj.show = !0 : $scope.obj.show = !1 - }, !0), $scope.onReplaceButtonClicked = function() { - if (LoginModel.getLoggedIn()) { - $scope.hideTooltip(), $scope.obj.disabled = !0, ReadClipsOnFSService.listPurchasesOnFS(function() { - console.log("DragAndDropController fs items listed, call onClipsFSCollected"), ReplaceService.onClipFSCollected() - }); - var ga = { - ec: "replace%20with%20hires" - }; - AnalyticsService.sendData(ga) - } else $scope.$root.$emit("modal not logged in", [ERROR]) - }, $scope.onReplaceButtonOver = function() { - $timeout(function() { - $("#replaceButton").trigger("show") - }, 0) - }, $scope.onReplaceButtonOut = function() { - $scope.hideTooltip() - }, $scope.hideTooltip = function() { - $timeout(function() { - $("#replaceButton").trigger("hide") - }, 0) - } -}), app.controller("SearchController", function($scope, ViewStateService, SearchModel, ViewStateModel, AnalyticsService) { - $scope.obj = { - filters: MEDIA_TYPES, - direction: "down", - showFilters: !1, - view: "search", - styleInput: "search-input-reg" - }, $scope.viewStateModel = function() { - return ViewStateModel.getState() - }, $scope.$watch($scope.viewStateModel, function() { - $scope.obj.view = ViewStateModel.getState(), 0 < THIRD_PARTY.length && ($scope.obj.styleInput = "search-input-tp") - }, !0), resizePanel = function() { - var numOfTotalResults = SearchModel.searchResultItems.length, - numOfResults = SearchModel.numOfResults, - rect = window.innerWidth * window.innerHeight; - 0 < numOfResults && numOfResults != numOfTotalResults && numOfTotalResults < rect / 25e3 && "search" == ViewStateModel.getState() && (SearchModel.isSearching || (console.log("SearchController resize, new search"), SearchModel.isSearching = !0, SearchModel.resultType = "add", SearchModel.page = SearchModel.page + 1, ViewStateService.viewRequested("search"))) - }, $scope.obj.selected = $scope.obj.filters[0], $scope.$root.$on("filters button clicked", function(event, state) { - $scope.obj.showFilters = state - }), $scope.filtersRequested = function() { - $scope.obj.showFilters = !$scope.obj.showFilters, $scope.$root.$emit("filters button clicked", $scope.obj.showFilters) - }, $scope.onChange = function(val) { - var sortID; - switch (console.log("SearchController onChange: ", val), $scope.obj.selected = val, $scope.obj.open = !1, $scope.obj.selected) { - case "Footage": - sortID = BM_VIDEO; - break; - case "After Effects": - sortID = BM_AFTER_EFFECTS; - break; - case "Music": - sortID = BM_MUSIC; - break; - case "SFX": - sortID = BM_SFX; - break; - case "Public Domain": - sortID = BM_PUBLIC_DOMAIN; - break; - case "Photos": - sortID = BM_PHOTO; - break; - case "Illustrations": - sortID = BM_ILLUSTRATIONS - } - SearchModel.sumOfBitmasks = sortID, console.log("SearchController changed, selected, bm: ", SearchModel.sumOfBitmasks), $scope.$root.$emit("media filter change", sortID), $scope.search() - }, $scope.setCurrent = function(val) { - $scope.obj.selected = val - }, $scope.toggled = function(open) { - $scope.obj.direction = open ? "dropup" : "down" - }, $scope.search = function() { - var query = document.getElementById("search").value; - "Search Pond5..." === query && (query = ""); - var ga = { - ec: "search" - }; - ga.ea = $scope.obj.selected.replace(/ /g, "%20"), ga.el = query.replace(/ /g, "%20"), AnalyticsService.sendData(ga), SearchModel.query = query, SearchModel.resultType = "replace", SearchModel.page = 0, SearchModel.sumOfBitmasks === BM_PUBLIC_DOMAIN && (SearchModel.query = SearchModel.query + " editorial:1"), console.log("SearchController search: ", query, SearchModel.sumOfBitmasks, SearchModel.resultType, SearchModel.page), ViewStateService.viewRequested("search") - }, $scope.searchButtonClicked = function() { - $scope.search() - }, $scope.enterThis = function() { - 13 === event.keyCode && $scope.search() - }, $scope.onSearchIconClicked = function() { - ViewStateService.viewRequested("search") - } -}); -var SellController = function($scope, AnalyticsService) { - $scope.sellClicked = function() { - var ga = { - ec: "sell%20media" - }; - console.log("SellController ga", ga), AnalyticsService.sendData(ga), opn("https://www.pond5.com/index.php?page=my_uploads") - } -}; -SellController.$inject = ["$scope", "AnalyticsService"], app.controller("SidebarController", function($scope, ViewStateModel, ViewStateService, AnalyticsService) { - $scope.obj = { - view: "search" - }, $scope.viewStateModel = function() { - return ViewStateModel.getState() - }, $scope.$watch($scope.viewStateModel, function() { - $scope.obj.view = ViewStateModel.getState() - }), $scope.onDownloadsIconClicked = function() { - $scope.$root.$emit("views requested", "downloads"), ViewStateService.viewRequested("downloads"); - var ga = { - ec: "downloads" - }; - AnalyticsService.sendData(ga) - }, $scope.onPreviewsIconClicked = function() { - ViewStateService.viewRequested("previews"); - var ga = { - ec: "imported%20previews" - }; - AnalyticsService.sendData(ga) - }, $scope.onDestinationIconClicked = function() { - $scope.$root.$emit("modal add destination requested"); - var ga = { - ec: "add%20destination" - }; - AnalyticsService.sendData(ga) - } -}), app.controller("SubTopRowController", function($scope, ViewStateModel, BinsModel, SearchModel, CartModel, PurchasesModel, UserModel, AnalyticsService) { - function onViewStateChange() { - var title; - switch (ViewStateModel.getState()) { - case "downloads": - title = "MY DOWNLOADS"; - break; - case "previews": - title = "MY IMPORTED PREVIEWS"; - break; - case "cart": - title = "MY CART"; - break; - case "freebies": - title = "50 FREE MEDIA CLIPS"; - break; - case "bins": - console.log("SubTopRowController selected bin name:", BinsModel.showBin.name), title = "COLLECTION: " + BinsModel.showBin.name; - break; - case "search": - title = 0 < SearchModel.query.length ? SearchModel.query.toUpperCase() : ""; - break; - default: - title = "" - } - $scope.obj.title = title, "search" == ViewStateModel.getState() ? $scope.obj.showDropdown = !0 : $scope.obj.showDropdown = !1, "cart" == ViewStateModel.getState() ? $scope.obj.showCreditsWrapper = !0 : $scope.obj.showCreditsWrapper = !1, $scope.showClearAll() - } - $scope.obj = { - showFilters: !1, - titleClass: "sub-top-row-title-no-filters", - showClearAll: !1, - showDropdown: !0, - showCreditsWrapper: !1, - credits: 0 - }, $scope.$root.$on("on cart total", function(event) { - $scope.obj.credits = CartModel.getCartTotal().creditsData.availableSum - }), $scope.cartModel = function() { - return CartModel.cartVO - }, $scope.$watch($scope.cartModel, function() { - $scope.showClearAll() - }), $scope.$root.$on("bin selected", function(event) { - onViewStateChange() - }), $scope.viewStateModelQuery = function() { - return SearchModel.query - }, $scope.$watch($scope.viewStateModelQuery, onViewStateChange), $scope.viewStateModel = function() { - return ViewStateModel.getState() - }, $scope.$watch($scope.viewStateModel, onViewStateChange), $scope.showClearAll = function() { - "cart" == ViewStateModel.getState() && 0 < CartModel.cartVO.items.length ? $scope.obj.showClearAll = !0 : $scope.obj.showClearAll = !1 - }, $scope.$root.$on("filters button clicked", function(event, state) { - $scope.obj.titleClass = state ? "sub-top-row-title-filters" : "sub-top-row-title-no-filters" - }), $scope.onClearCartClicked = function() { - if (0 != CartModel.cartVO.items.length) { - for (var ids = "", i = 0; i < CartModel.cartVO.items.length; i++) i < CartModel.cartVO.items.length ? ids += CartModel.cartVO.items[i].id + "," : ids += CartModel.cartVO.items[i].id; - $scope.$root.$emit("clear cart requested", [ids]) - } - }, $scope.buyCreditsClicked = function() { - var ga = { - ec: "buy%20credits" - }; - console.log("CreditsController ga", ga), AnalyticsService.sendData(ga), $scope.$root.$emit("modal buy credits requested"), console.log("SubTopRowController button clicked") - } -}), app.controller("TileListItemController", function($scope, Service, BinsModel, ImportedPreviewsService, ViewStateModel, LoginModel, ReplaceModel, DownloadModel) { - $scope.childObj = {}, $scope.childObj.addedToCart = !1, $scope.childObj.addedToBin = !1, $scope.allowDownload = !0, $scope.childObj.cartClicked = !1, $scope.childObj.binClicked = !1, $scope.childObj.showEditorial = !0, $scope.childObj.viewState = "search", $scope.childObj.notification = "", "FCPX" === HOST_NAME ? $scope.childObj.importTooltip = "CLICK TO DOWNLOAD" : $scope.childObj.importTooltip = "CLICK TO IMPORT", $scope.viewState = function() { - return ViewStateModel.getState() - }, $scope.$watch($scope.viewState, function() { - $scope.childObj.viewState = ViewStateModel.getState() - }, !0), $scope.$root.$on("added to cart", function(event) { - $scope.childObj.cartClicked && ($scope.childObj.addedToCart = !0), setTimeout(function() { - $scope.childObj.cartClicked = !1, $scope.childObj.addedToCart = !1 - }, 1e3) - }), $scope.$root.$on("added to bin", function(event) { - $scope.childObj.binClicked && ($scope.childObj.addedToBin = !0), setTimeout(function() { - $scope.childObj.binClicked = !1, $scope.childObj.addedToBin = !1 - }, 1e3) - }), $scope.itemHovered = function(e) { - $scope.childObj.showMenu = !0, $scope.$root.$emit("start preview", $scope.item, e.clientX) - }, $scope.itemLeft = function() { - $scope.childObj.showMenu = !1, $scope.$root.$emit("stop preview", $scope.item) - }, $scope.opaqueClicked = function() { - console.log("TileListItemController opaqueClicked", $scope.allowDownload), $scope.allowDownload && ($scope.allowDownload = !1, $scope.$root.$emit("download requested", [$scope.item]), ImportedPreviewsService.saveItem($scope.item.id), $scope.$root.$emit("stop preview", $scope.item)), setTimeout(function() { - $scope.allowDownload = !0 - }, 2e3) - }, $scope.overInfoIcon = function() { - $scope.$root.$emit("preview info icon over") - }, $scope.outInfoIcon = function() { - $scope.$root.$emit("preview info icon out") - }, $scope.binIconClicked = function() { - console.log("TileListItemController binIconClicked"), LoginModel.loggedIn ? 0 < BinsModel.bins.length ? (console.log("TileListItemController binIconClicked show notification"), Service.modifyBin(BinsModel.addToBin.id, $scope.item.id), $scope.childObj.notification = "Added to the collection!", $scope.childObj.binClicked = !0, setTimeout(function() { - $scope.childObj.binClicked = !1, $scope.childObj.addedToBin = !1 - }, 4e3), $scope.childObj.binClicked = !0) : $scope.$root.$emit("modal simple requested", ["You don't have Collections", "In order to add clips to a Collection you first need to create a Collection"]) : $scope.$root.$emit("modal not logged in", [ERROR]) - }, $scope.cartIconClicked = function() { - $scope.childObj.notification = "Added to the cart successfully!", $scope.childObj.cartClicked = !0, setTimeout(function() { - $scope.childObj.cartClicked = !1, $scope.childObj.addedToCart = !1 - }, 4e3), Service.getFormats($scope.item) - }, $scope.trashIconClicked = function() { - $scope.$root.$emit("stop preview", $scope.item), "bins" === ViewStateModel.getState() ? Service.modifyBin(BinsModel.binVO.id, "", $scope.item.id) : "previews" === ViewStateModel.getState() && ImportedPreviewsService.deleteItem($scope.item.id) - }, $scope.linkClicked = function() { - opn("https://www.pond5.com/item/" + $scope.item.id) - } -}), app.controller("TileListSearchController", function($scope, SearchModel, Service) { - $scope.obj = { - showDeleteIcon: !1 - }, $scope.searchItems = function() { - if (SearchModel.searchResultVO) return SearchModel.searchResultVO.items - }, $scope.$watch($scope.searchItems, function() { - SearchModel.searchResultVO && ($scope.obj.items = SearchModel.searchResultItems) - }) -}), app.controller("TileListPreviewsController", function($scope, PreviewsModel) { - $scope.obj = { - showDeleteIcon: !0 - }, $scope.previewItems = function() { - if (PreviewsModel.previewsVO) return PreviewsModel.previewsVO.items - }, $scope.$watch($scope.previewItems, function() { - if (PreviewsModel.previewsVO) { - console.log("TileListPreviewsController: ", PreviewsModel.previewsVO), PreviewsModel.previewsVO.items.reverse(); - for (var previews = PreviewsModel.previewsVO.items, nonAEpreviews = [], i = 0; i < previews.length; i++) "AE" != previews[i].type && nonAEpreviews.push(previews[i]); - $scope.obj.items = nonAEpreviews - } - }) -}), app.controller("TileListBinsController", function($scope, BinsModel) { - $scope.obj = { - showDeleteIcon: !0 - }, $scope.binItems = function() { - if (BinsModel.binVO) return BinsModel.getBinVO() - }, $scope.$watch($scope.binItems, function() { - BinsModel.binVO && ($scope.obj.items = BinsModel.binVO.items) - }, !0) -}), app.controller("TileListFreebiesController", function($scope, FreebiesModel) { - $scope.obj = { - showDeleteIcon: !1 - }, $scope.freeItems = function() { - if (FreebiesModel.freebiesVO) return FreebiesModel.freebiesVO.items - }, $scope.$watch($scope.freeItems, function() { - FreebiesModel.freebiesVO && ($scope.obj.items = FreebiesModel.freebiesVO.items) - }) -}), app.controller("TransactionController", function($scope, ViewStateModel, ViewStateService, Service, AnalyticsService, CheckOutModel, ReplaceModel) { - $scope.obj = { - url: "", - show: !1 - }, $scope.CheckOutModel = function() { - return CheckOutModel - }, $scope.$watch($scope.CheckOutModel, function() { - if (CheckOutModel.checkOutURL) { - (new Date).getTime(); - $scope.obj.url = CheckOutModel.checkOutURL, $scope.obj.show = !0, CheckOutModel.checkOutURL = "", $("body,html").css("overflow", "hidden") - } - }, !0), window.parent.addEventListener("message", function() { - switch (ViewStateModel.allowPreviews = !0, console.log("TransactionController postMessage: ", event.data), event.data) { - case "PAID": - ReplaceModel.getState() === NOT_PURCHASED ? Service.getPurchases() : ($scope.$root.$emit("modal simple requested", PURCHASE_SUCCESSFULL), ViewStateService.viewRequested("downloads")), $scope.$root.$emit("purchase complete"), Service.getUserInfo(), console.log("TransactionController CC payment success"); - break; - case "CANCELED": - $scope.$root.$emit("modal simple requested", PURCHASE_CANCELED); - break; - default: - $scope.$root.$emit("modal simple requested", [ERROR, "UNKNOWN"]) - } - $scope.obj.show = !1, console.log("TransactionController onDone, show:", $scope.obj.show), $scope.$root.$emit("checkout complete"), $("body,html").css("overflow", "visible") - }, !1) -}), app.directive("enter", function() { - return function(scope, element, attrs) { - element.bind("keydown", function() { - 13 === event.which && scope.$apply(attrs.enter) - }) - } -}), app.directive("enterFooter", function() { - return function(scope, element, attrs) { - element.bind("mouseenter", function() { - element.children()[0].style.color = "#ccc" - }) - } -}), app.directive("leaveFooter", function() { - return function(scope, element, attrs) { - element.bind("mouseleave", function() { - element.children()[0].style.color = "#969493" - }) - } -}), app.directive("repositionImage", function() { - return { - restrict: "A", - link: function(scope, elem, attrs) { - elem.on("load", function() { - 108 < $(this).height() && elem.addClass("high") - }) - } - } -}), app.directive("rotate", function() { - return { - restrict: "A", - link: function(scope, element, attrs) { - scope.$watch(attrs.rotate, function(dir) { - var r = "rotate(" + ("up" === dir ? 180 : 0) + "deg)"; - element.css({ - "-webkit-transform": r - }) - }) - } - } -}), app.directive("whenScrolled", ["$window", "ScrollService", function($window, ScrollService) { - return function(scope, elm, attr) { - elm[0]; - angular.element($window).bind("scroll", function() { - ScrollService.onScroll() - }) - } -}]), app.directive("scrollTop", [function() { - return { - restrict: "A", - link: function(scope, $elm, attr) { - scope.$root.$on("scroll progress to top", function() { - $elm.animate({ - scrollTop: 0 - }, "slow") - }) - } - } -}]), app.directive("dragMe", function() { - return { - restrict: "A", - link: function(scope, elem, attr, ctrl) { - elem.draggable() - } - } -}), app.directive("onHoverInfoCart", function() { - return { - link: function(scope, element, attrs) { - element.bind("mouseenter", function($event) { - initialMouseX = $event.clientX, initialMouseY = $event.clientY, scope.$root.$emit("cart icon over", initialMouseX, initialMouseY) - }), element.bind("mouseleave", function() { - scope.$root.$emit("cart icon out") - }) - } - } -}), app.directive("onHoverPreview", function() { - return { - link: function(scope, element, attrs) { - element.bind("mouseenter", function($event) { - var previewX, previewY, tileX = element[0].getBoundingClientRect().left; - previewX = tileX < 310 ? tileX + 220 : tileX - 400, (previewY = element[0].getBoundingClientRect().top - 200) < 20 && (previewY = 20), 340 < previewY && (previewY = 340); - var cols = document.getElementsByClassName("preview"); - for (i = 0; i < cols.length; i++) cols[i].style.left = previewX.toString() + "px", cols[i].style.top = previewY.toString() + "px" - }) - } - } -}), app.filter("to_trusted", ["$sce", function($sce) { - return function(text) { - return $sce.trustAsHtml(text) - } -}]), app.filter("trusted", ["$sce", function($sce) { - return function(url) { - return $sce.trustAsResourceUrl(url) - } -}]), app.filter("secondsToDateTime", [function() { - return function(seconds) { - return new Date(1970, 0, 1).setSeconds(seconds) - } -}]), app.directive("closeCollectionsList", function($document) { - return { - restrict: "A", - link: function(scope, elem, attr, ctrl) { - elem.bind("click", function(e) { - e.stopPropagation() - }), $document.bind("click", function() { - scope.$apply(attr.closeCollectionsList) - }) - } - } -}), app.directive("fieldValidation", function() { - return { - require: "ngModel", - link: function(scope, element, attr, mCtrl) { - mCtrl.$parsers.push(function(value) { - return /^\w+$/.test(value) && 1 < value.toString().length || 0 == value.toString().length ? (mCtrl.$setValidity("charE", !0), console.log("directive valid true")) : (mCtrl.$setValidity("charE", !1), console.log("directive valid false")), value - }) - } - } -}), app.directive("vatValidation", function() { - return { - require: "ngModel", - link: function(scope, element, attr, mCtrl) { - mCtrl.$parsers.push(function(value) { - return /^\w+$/.test(value) && 2 < value.toString().length || 0 == value.toString().length ? (mCtrl.$setValidity("charE", !0), console.log("directive valid true")) : (mCtrl.$setValidity("charE", !1), console.log("directive valid false")), value - }) - } - } -}), app.directive("restrictInput", [function() { - return { - restrict: "A", - link: function(scope, element, attrs) { - var ele = element[0], - regex = RegExp(attrs.restrictInput), - value = ele.value; - ele.addEventListener("keyup", function(e) { - regex.test(ele.value) ? value = ele.value : ele.value = value - }) - } - } -}]), app.filter("searchFilter", function() { - return function(input, param1) { - if (console.log("------------------------------------------------- begin dump of custom parameters"), console.log("searchFilter input: ", input), input && input.length) { - console.log("searchFilter param1: ", param1); - var filteredItems = []; - for (i = 0; i < input.length; i++) input[i].fps == param1 && filteredItems.push(input[i]); - return filteredItems - } - } -}), PURCHASE_SUCCESSFULL = ["Your purchase has been successfull!", "Your items are now ready to download."], PURCHASE_CANCELED = ["Canceled.", "Purchase was canceled."], ERROR = "Oops, something went wrong...", NO_RESULTS = ["Your search returned no results", ""], BM_VIDEO = 15, BM_MUSIC = 16, BM_SFX = 32, BM_PHOTO = 128, BM_ILLUSTRATIONS = 1024, BM_AFTER_EFFECTS = 64, BM_PUBLIC_DOMAIN = 16384, MODE = "live", THIRD_PARTY = "", TARGET_APP = "", GA_TRACKING_CODE = "UA-60083218-9", DEFAULT = "not replacing", MISSING_ITEMS = "missing items", NOT_PURCHASED = "not purchased", NOT_DOWNLOADED = "not downloaded", PURCHASED_AND_DOWNLOADED = "purchased and downloaded"; -var BASE_URL = "https://plugin.pond5.com/", - NO_RESULTS_ICON = BASE_URL + "pond5_shared/images/no_results_icon.png", - DRAGNDROP_IMG = BASE_URL + "pond5_shared/images/intro-icons/dragndrop.png", - STATE_IMG = BASE_URL + "pond5_shared/images/intro-states/step", - STATE_FCP_IMG = BASE_URL + "pond5_shared/images/intro-states-fcp/step", - DOWNLOAD_IMG = BASE_URL + "pond5_shared/images/intro-icons/download.png", - CART_IMG = BASE_URL + "pond5_shared/images/intro-icons/cart.png", - PREVIEWS_IMG = BASE_URL + "pond5_shared/images/intro-icons/previews.png", - DUMMY_IMG = BASE_URL + "pond5_shared/images/intro-icons/dummy.png", - CLEAR_CART_TRASH_IMG = BASE_URL + "pond5_shared/images/clear-cart-trash-icon.png", - CART_BUTTON_IMG = BASE_URL + "pond5_shared/images/cartButtonIcon.png", - PROGRESS_CLOSE_IMG = BASE_URL + "pond5_shared/images/progress-close-icon.png", - LOGO_IMG = BASE_URL + "pond5_shared/images/logo-white.png", - MODAL_SIMPLE_HTML = BASE_URL + "pond5_shared/views/modals/modalSimple.html", - MODAL_ADD_DESTINATION_HTML = BASE_URL + "pond5_shared/views/modals/modalAddDestination.html", - MODAL_ADD_COLLECTION_HTML = BASE_URL + "pond5_shared/views/modals/modalAddCollection.html", - MODAL_ADD_COLLECTION_CONFIRMATION_HTML = BASE_URL + "pond5_shared/views/modals/modalAddCollectionConfirmation.html", - MODAL_SELECT_SEQUENCES_HTML = BASE_URL + "pond5_shared/views/modals/modalSelectSequences.html", - MODAL_INTRO_HTML = BASE_URL + "pond5_shared/views/modals/modalIntro.html", - MODAL_ADD_TO_CART_HTML = BASE_URL + "pond5_shared/views/modals/modalAddToCart.html", - MODAL_BILLING_ADDRESS_HTML = BASE_URL + "pond5_shared/views/modals/modalBillingAddress.html", - MODAL_CHOOSE_BILLING_INFO_HTML = BASE_URL + "pond5_shared/views/modals/modalChooseBillingInfo.html", - MODAL_CHOOSE_FORMAT_HTML = BASE_URL + "pond5_shared/views/modals/modalChooseFormat.html", - MODAL_CHOOSE_VERSION_HTML = BASE_URL + "pond5_shared/views/modals/modalChooseVersion.html", - MODAL_FREEBIES_HTML = BASE_URL + "pond5_shared/views/modals/modalFreebies.html", - MODAL_LOGIN_HTML = BASE_URL + "pond5_shared/views/modals/modalLogin.html", - MODAL_NOT_LOGGED_IN_HTML = BASE_URL + "pond5_shared/views/modals/modalNotLoggedIn.html", - MODAL_PROMO_CODE_HTML = BASE_URL + "pond5_shared/views/modals/modalPromoCode.html", - MODAL_REMOVE_COLLECTION_HTML = BASE_URL + "pond5_shared/views/modals/modalRemoveCollection.html", - MODAL_REPLACE_HTML = BASE_URL + "pond5_shared/views/modals/modalReplace.html", - MODAL_REPLACE_WARNING_HTML = BASE_URL + "pond5_shared/views/modals/modalReplaceWarning.html", - MODAL_BUY_CREDITS_HTML = BASE_URL + "pond5_shared/views/modals/modalBuyCredits.html", - COLLECTIONS_LIST_HTML = BASE_URL + "pond5_shared/views/collectionsList.html"; -$(function() { - Offline.options = { - checkOnLoad: !0, - checks: { - image: { - url: function() { - return "https://plugin.pond5.com/pond5_shared/images/logo-white.png?_=" + Math.floor(1e9 * Math.random()) - } - }, - active: "image" - } - } -}), app.service("AppModel", ["$rootScope", function($rootScope) { - var path = require("path"), - dirHomePond5 = getUserHome() + path.sep + "pond5", - dirImports = dirHomePond5 + path.sep + "imports", - dirPrefs = dirHomePond5 + path.sep + "prefs", - dirDestinations = dirHomePond5 + path.sep + "destinations", - dirDefaultLib = path.sep, - dirUser = dirHomePond5 + path.sep + "user", - result = (dirDefaultLib = dirHomePond5 + path.sep + "defaultLib", { - OS: "", - baseFolders: [], - currentBaseFolder: "", - previewsDir: "", - purchasedDir: "", - defaultLib: "", - defaultLibName: "", - defaultLibPath: "", - targetApp: "", - setEnv: function() { - result.setOS(os.platform()), $rootScope.$emit("environment set") - }, - getOS: function() { - return result.OS - }, - setOS: function(s) { - result.OS = s - }, - getDocumentsPath: function() { - return os.homedir() + path.sep + "Documents" - }, - getDirHomePond5: function() { - return dirHomePond5 - }, - getDirImports: function() { - return dirImports - }, - getDirDestinations: function() { - return dirDestinations - }, - getDirPrefs: function() { - return dirPrefs - }, - getDirUser: function() { - return dirUser - }, - getDestinationsXML: function() { - return result.getDirDestinations() + path.sep + "destinations.xml" - }, - getUserXML: function() { - return result.getDirUser() + path.sep + "user.xml" - }, - getPreferencesXML: function() { - return result.getDirPrefs() + path.sep + "preferences.xml" - }, - getDirDefaultLib: function() { - return dirDefaultLib - }, - getDefaultLib: function() { - return result.defaultLib - }, - setDefaultLib: function(path) { - "/" == path.substr(path.length - 1) && (path = path.slice(0, -1)), result.setDefaultLibName(path), result.setDefaultLibPath(path), result.defaultLib = path - }, - getDefaultLibName: function() { - return result.defaultLibName - }, - setDefaultLibName: function(path) { - var n = path.lastIndexOf("/"); - result.defaultLibName = path.substring(n + 1).replace(".fcpbundle", "") - }, - getDefaultLibPath: function() { - return result.defaultLibPath - }, - setDefaultLibPath: function(path) { - result.defaultLibPath = path.substring(0, path.lastIndexOf("/")) - }, - getDefaultLibXML: function() { - return result.getDirDefaultLib() + path.sep + "defaultLib.xml" - }, - getTargetApp: function() { - return result.targetApp - }, - setTargetApp: function(app) { - result.targetApp = app - } - }); - return result -}]), app.factory("BillingInfoModel", ["$rootScope", function($rootScope) { - var info = { - onBillingInfo: function(data) { - info.setBillingInfo(data.commands[0]), info.getBillingInfo().forEach(function(item) { - item.isdefault && info.setDefaultInfo(item) - }) - }, - setBillingInfo: function(data) { - info.billingInfo = data - }, - getBillingInfo: function() { - return info.billingInfo - }, - setDefaultInfo: function(data) { - info.defaultInfo = data - }, - getDefaultInfo: function() { - return info.defaultInfo - } - }; - return info -}]), app.service("BinsModel", ["$rootScope", function($rootScope) { - var result = { - binsVO: null, - bins: [], - binVO: null, - showBin: null, - addToBin: null, - onBins: function(data) { - result.binsVO = new BinsVO(data.commands[0]), result.bins = result.binsVO.bins, $rootScope.$emit("onBins") - }, - onBin: function(data) { - result.setBinVO(new BinVO(data.commands[0])) - }, - onActiveBin: function(data) { - result.bins.forEach(function(bin) { - bin.id == data.commands[0].binid && (result.addToBin = bin) - }), $rootScope.$emit("active bin changed", result.addToBin) - }, - setBinVO: function(data) { - result.binVO = data - }, - getBinVO: function() { - return result.binVO - } - }; - return result -}]); -var BinsVO = function BinsVO(data) { - var i; - for (this.bins = [], i = 0; i < data.bins.length; i += 1) { - var bin = {}; - bin.name = data.bins[i].name, bin.abbrBinName = getAbbrName(bin.name, 17), bin.id = data.bins[i].id, bin.total = data.bins[i].tot, bin.selected = !1, this.bins[i] = bin - } - this.bins.sort(compare), BinsVO.prototype = { - toString: function() { - console.log("bins: " + this.bins) - } - } - }, - BinVO = function BinVO(data) { - var itemVO, i; - this.items = [], this.id = data.binid, this.name = data.name, this.jpegBase = "http://ec.pond5.com/s3/", console.log("BinVO id: ", data.binid, data.name); - var filterVS = 0; - for (filterVS = "AEFT" == HOST_NAME ? 200 : 102, i = 0; i < data.items.length; i += 1) parseInt(data.items[i].vs) <= filterVS && (itemVO = new ItemVO(data.items[i], data.icon_base, data.flv_base, "", this.jpegBase), this.items.push(itemVO)); - BinVO.prototype = { - toString: function() { - console.log("name & id: ", this.id, this.name) - } - } - }; -app.factory("CartModel", ["$rootScope", "ReplaceModel", function($rootScope, ReplaceModel) { - $rootScope.$on("on cart", function(event, data) { - result.onCart(data) - }), $rootScope.$on("on cart total", function(event, data) { - result.onCartTotal(data) - }), $rootScope.$on("formats complete", function(event, item, formats) { - console.log("CartModel onCart ReplaceModel.getState(): ", ReplaceModel.getState()), result.onFormats(item, formats) - }); - var result = { - cartVO: [], - cartTotal: null, - onCart: function(data) { - result.cartVO = new ItemsVO(data.commands[0]) - }, - onCartTotal: function(data) { - result.setCartTotal(data.commands[0]) - }, - onFormats: function(item, formats) { - if (console.log("CartModel onFormats, num of formats for id: ", item, formats.length), 1 < formats.length) { - var uniqueResFormats = _.uniq(formats, function(p) { - return p.ti - }); - $rootScope.$emit("on add to cart clicked", uniqueResFormats) - } else { - var apiObj = { - fn: "modifyCart", - args: [item.id, ""] - }; - $rootScope.$emit("api call", apiObj) - } - }, - setCartTotal: function(data) { - result.cartTotal = data - }, - getCartTotal: function() { - return result.cartTotal - } - }; - return result -}]), app.factory("CheckOutModel", ["$sce", function($sce) { - var result = { - onPurchase: function(data) { - console.log("CheckOutModel onPurchase, url: ", data.commands[0].url); - (new Date).getTime(); - result.checkOutURL = $sce.trustAsResourceUrl(data.commands[0].url), console.log("CheckOutModel onPurchase, url: ", result.checkOutURL) - } - }; - return result -}]), app.factory("DownloadModel", ["$rootScope", "PurchasesModel", "ReplaceModel", function($rootScope, PurchasesModel, ReplaceModel) { - var result = { - binBatch: null, - itemsDownloadList: [], - selectedVersion: 0, - downloadingBatchURLs: !1, - urlCounter: 0, - downloadCounter: -1, - stayAwake: !1, - onGetPurchaseURL: function(data) { - var item = result.getVersionByID(data.commands[0].bid); - item && (item.hiresURL = data.commands[0].url, item.downloadType = "purchase", "AE" == item.vs && (item.type = item.vs), $rootScope.$emit("download requested", [item])) - }, - onGetAllPurchaseURLs: function(data) { - var i, purchase, purchases = []; - for (ReplaceModel.getState() === DEFAULT ? purchases = PurchasesModel.purchasesVO.items : ReplaceModel.getState() === NOT_DOWNLOADED && (purchases = ReplaceModel.missingDownloads), result.urlCounter++, i = 0; i < purchases.length; i += 1) { - purchase = purchases[i]; - var dataItem = data.commands[0]; - for (k = 0; k < purchase.formats.length; k += 1) purchase.formats[k].id == dataItem.bid && (purchase.hiresURL = dataItem.url, purchase.downloadType = "purchase"); - purchase.id == dataItem.bid && (purchase.hiresURL = dataItem.url, purchase.downloadType = "purchase", purchase.versions && 0 < purchase.versions.length && (purchase.vs = purchase.versions[0].vs)) - } - purchases = purchases.filter(function(v, i, a) { - return a.indexOf(v) == i - }), result.urlCounter === purchases.length && ($rootScope.$emit("download requested", purchases), result.urlCounter = 0, result.downloadingBatchURLs = !1) - }, - getVersionByID: function(id) { - var foundItem; - if (PurchasesModel.purchasesVO.items.forEach(function(item) { - item.id === id && (item.parentFormatID && (item.versions[result.selectedVersion].parentFormatID = item.parentFormatID), foundItem = item.versions[result.selectedVersion]) - }), foundItem) return foundItem - } - }; - return result -}]), app.factory("FreebiesModel", [function() { - var result = { - onFreebies: function(data) { - result.freebiesVO = new ItemsVO(data.commands[0]) - } - }; - return result -}]); -var HiresVO = function HiresVO(dest, name) { - this.dest = dest, this.name = name, this.path = dest + name, this.id = name.split(" ")[1], this.replace = !1, this.type = "", this.nameFCP = this.name.replaceAll(" ", "%20"), this.nameFCP = this.nameFCP.replaceAll("-", "%2D"), this.nameFCP = this.nameFCP.replaceAll("&", "and"), this.pathFCP = "file://" + this.path.replaceAll(" ", "%20"), this.pathFCP = this.pathFCP.replaceAll("-", "%2D"), this.pathFCP = this.pathFCP.replaceAll("&", "and"), HiresVO.prototype = { - toString: function() { - return "\nHiresVO path: " + this.path + "\nname: " + this.name + "\nid: " + this.id + "\nreplace: " + this.replace - } - } - }, - ItemsVO = function ItemsVO(data) { - var itemVO, i; - for (this.tot_nbr_rows = data.tot_nbr_rows, this.max_per_page = data.max_per_page, this.nbr_footage = data.nbr_footage, this.nbr_music = data.nbr_music, this.nbr_sfx = data.nbr_sfx, this.nbr_total = data.nbr_total, this.items = [], i = 0; i < data.items.length; i += 1) itemVO = new ItemVO(data.items[i], data.icon_base, data.flv_base, ""), this.items[i] = itemVO; - ItemsVO.prototype = { - toString: function() { - console.log("vs: " + this.vs) - } - } - }, - ItemVO = function ItemVO(data, iconBase, flvBase, parentID) { - var getURL; - this.selectedVersion = 0, this.name = data.n, this.abbrName = getAbbrName(this.name, 25), this.abbrTileName = getAbbrName(this.name, 22), this.abbrListName = getAbbrName(this.name, 40), this.artistName = getAbbrName(data.artistname, 40), this.id = data.id, this.title = data.ti, this.vr360 = data.vr360, data.pr < .001 ? this.price = "0" : this.price = data.pr, this.priceRange = data.pricerange, this.vs = getConvertedVideoStandard(data.vs), this.downloadType = "preview", this.downloadURL, this.downloadDestination = "", this.downloading = !1, this.progressPerc = "", this.progressMB = "", this.progressName = "", this.parentFormatID = "", this.canceled = !1, this.completed = !1, this.imported = !1, this.inCart = !1, this.inDownloads = !1, this.selected = !1, this.formats = [], this.versions = [], this.ox = data.ox, this.oy = data.oy, this.ar = getAspectRatio(data.ar), this.ar || (this.ar = "n/a"), this.aq = data.aq, this.dur = data.dur, data.fps ? this.fps = data.fps : this.fps = "n/a", data.ti && (this.title = data.ti), data.tb && (this.subTitle = data.tb), data.i && (this.additionalInfo = data.i), data.id ? this.id = data.id : this.id = parentID, 0 === this.id.length && (this.id = parentID), this.offset = data.so, this.transactionID = data.tr, this.expirationDate = data.exp, this.versionID = data.v, this.videoCodec = data.codg, this.audioCodec = data.coda, this.extension = data.ext, this.version = data.bitoffset, this.type = getMediaType(this.vs), this.baseURL = flvBase || "https://api-cdn.pond5.com/", getURL = function(id, type, baseURL) { - var url; - switch (type) { - case "icon": - url = iconBase + ExtendedID.extend(id) + "_iconv.jpeg"; - break; - case "H264": - url = baseURL + ExtendedID.extend(id) + "_main_xl.mp4"; - break; - case "vr360": - url = baseURL + ExtendedID.extend(id) + "_main360.mp4"; - break; - case "mov": - url = baseURL + ExtendedID.extend(id) + "_prev_264.mov"; - break; - case "flv": - url = baseURL + ExtendedID.extend(id) + "_prev_xl.flv"; - break; - case "mp3": - url = baseURL + ExtendedID.extend(id) + "_prev.mp3"; - break; - case "m4a": - url = baseURL + ExtendedID.extend(id) + "_prev.m4a"; - break; - case "icon large": - url = iconBase + ExtendedID.extend(id) + "_iconl.jpeg" - } - return url - }, this.iconURL = getURL(this.id, "icon", this.baseURL), this.iconLargeURL = getURL(this.id, "icon large", this.baseURL), this.vr360 ? this.h264URL = getURL(this.id, "vr360", this.baseURL) : this.h264URL = getURL(this.id, "H264", this.baseURL), this.mp3URL = getURL(this.id, "mp3", this.baseURL), this.m4aURL = getURL(this.id, "m4a", this.baseURL), ItemVO.prototype = {} - }; -app.factory("LoginModel", [function() { - var data = { - getLoggedIn: function() { - return data.loggedIn - }, - setLoggedIn: function(state) { - data.loggedIn = state - }, - getCX: function() { - return data.cx - }, - setCX: function(cx) { - data.cx = cx - }, - getCM: function() { - return data.cm - }, - setCM: function(cm) { - data.cm = cm - } - }; - return data -}]), app.service("MissingItemsModel", [function() { - return { - missingItemsVO: null - } -}]); -var MissingItemsVO = function MissingItemsVO(data) { - var i; - for (this.items = [], i = 0; i < data.items.length; i += 1) this.itemVO = new ItemVO(data.items[i], data.icon_base, data.flv_base), this.items[i] = this.itemVO; - MissingItemsVO.prototype = {} -}; -app.factory("PreviewsModel", [function() { - var result = { - onPreviews: function(data) { - console.log("PreviewsModel onPreviews: ", data), result.previewsVO = new ItemsVO(data.commands[0]) - } - }; - return result -}]); -var PreviewVO = function PreviewVO(dest, path) { - var parts = (this.path = path).split("/"); - this.name = parts[parts.length - 1], this.id = this.name.split(" ")[0], PreviewVO.prototype = { - toString: function() { - return "\nPreviewVO path: " + this.path + "\nname: " + this.name + "\nid: " + this.id - } - } -}; -app.service("PurchasesModel", ["$rootScope", "AnalyticsService", function($rootScope, AnalyticsService) { - $rootScope.$on("on purchases", function(event, data) { - result.onGetPurchases(data) - }), $rootScope.$on("purchase complete", function(event) { - console.log("PurchasesModel purchase complete handler"), result.sendGA = !0 - }); - var result = { - purchasesVO: [], - sendGA: !1, - onGetPurchases: function(data) { - result.purchasesVO = new PurchaseVO(data.commands[0]), $rootScope.$emit("on purchases vo", result.purchasesVO), console.log("PurchasesModel onGetPurchases result.purchasesVO: ", result.purchasesVO), result.sendGA && (AnalyticsService.sendData(result.purchasesVO, "transaction"), result.sendGA = !1) - } - }; - return result -}]); -var PurchaseVO = function PurchaseVO(data) { - var i; - this.items = []; - for ("AEFT" == HOST_NAME ? 200 : 102, i = 0; i < data.items.length; i += 1) { - var j; - for (this.itemVO = new ItemVO(data.items[i], data.icon_base, data.flv_base, data.items[i].bid), this.itemVO.transactionID = data.items[i].versions[0].tr, this.itemVO.name = data.items[i].versions[0].n, this.itemVO.abbrName = getAbbrName(this.itemVO.name, 30), this.itemVO.expirationDate = data.items[i].versions[0].exp, this.itemVO.parentFormatID = data.items[i].versions[0].vm, this.itemVO.type = getMediaType(getConvertedVideoStandard(data.items[i].versions[0].vs)), this.itemVO.aq = data.items[i].versions[0].aq, this.itemVO.versionID = data.items[i].versions[0].v, this.itemVO.version = data.items[i].versions[0].bitoffset, j = 0; j < data.items[i].versions.length; j += 1) this.itemVO.versions[j] = new ItemVO(data.items[i].versions[j], data.icon_base, data.flv_base, data.items[i].bid); - this.items.push(this.itemVO) - } - PurchaseVO.prototype = { - toString: function() { - console.log("name & id: ", this.items) - } - } -}; - -function checkNested(obj) { - for (var args = Array.prototype.slice.call(arguments), i = (obj = args.shift(), 0); i < args.length; i++) { - if (!obj.hasOwnProperty(args[i])) return !1; - obj = obj[args[i]] - } - return !0 -} - -function compare(a, b) { - return a.name < b.name ? -1 : a.name > b.name ? 1 : 0 -} - -function sortArgs() { - return Array.prototype.slice.call(arguments, 0).sort()[0] -} - -function getAspectRatio(as) { - var standard; - switch (as) { - case 1: - standard = "4:3"; - break; - case 2: - standard = "16:9 anamorphic"; - break; - case 3: - standard = "16:9 letterboxed"; - break; - case 4: - standard = "n/a"; - break; - case 5: - standard = "Other"; - break; - case 6: - standard = "16:9 native" - } - return standard -} - -function convertAspectRatio($max_x, $max_y, $aspect_quotient) { - var $out_x, $out_y; - return $aspect_quotient ? ($out_y = $max_y, $max_x < ($out_x = Math.round($max_y * parseFloat($aspect_quotient))) && ($out_x = $max_x, $out_y = Math.round($max_x / parseFloat($aspect_quotient))), new Point($out_x, $out_y)) : ($out_x = $max_x, $out_y = $max_y, new Point(370, 208)) -} -app.factory("ReplaceModel", ["$rootScope", function($rootScope) { - var result = { - clipsInSequences: [], - aeItemsinProjectView: [], - state: DEFAULT, - missingDownloads: [], - hiresOnFS: [], - previewsOnFS: [], - sequences: [], - setState: function(newState) { - result.state = newState, console.log("ReplaceModel STATE:", result.state), result.state === DEFAULT && $rootScope.$root.$emit("replacing complete") - }, - getState: function() { - return result.state - }, - getAEItems: function() { - return result.aeItemsinProjectView - }, - setAEItems: function(items) { - result.aeItemsinProjectView = items - }, - setSequenceNames: function(seqNames) { - result.sequences = []; - for (var i = 0; i < seqNames.length; i++) { - var obj = { - name: seqNames[i], - checked: !1 - }; - result.sequences[i] = obj - } - 0 < seqNames.length ? $rootScope.$root.$emit("modal select sequences", result.sequences) : ($rootScope.$root.$emit("modal simple requested", ["Replace With Hi-Res Clips - Warning", "The 'Replace With Hi-Res clips' button replaces lo-res previews with hi-res clips that you have purchased and downloaded.

There are currently no sequences in your project."]), result.setState(DEFAULT)) - }, - setSequences: function(sequences) { - result.sequences = []; - for (var i = 0; i < sequences.length; i++) sequences[i].checked = !1; - var newArray = []; - newArray.push(sequences[0]); - for (i = 1; i < sequences.length; i++) { - for (var j = 0; j < newArray.length; j++) newArray[j].name === sequences[i].name && (console.log("already exists ", i, j, sequences[i].name), 0, sequences[i].name = sequences[i].name + " (id: " + sequences[i].id + ")"); - newArray.push(sequences[i]) - } - result.sequences = newArray, console.log("ReplaceModel, sequences:", result.sequences), 0 < sequences.length ? $rootScope.$root.$emit("modal select sequences", result.sequences) : ($rootScope.$root.$emit("modal simple requested", ["Replace With Hi-Res Clips - Warning", "The 'Replace With Hi-Res clips' button replaces lo-res previews with hi-res clips that you have purchased and downloaded.

There are currently no sequences in your project."]), result.setState(DEFAULT)) - }, - setComps: function(comps) { - result.sequences = comps, $rootScope.$root.$emit("modal select comps", result.sequences) - }, - addHires: function(dest, files) { - for (var hiresVO, i = 0; i < files.length; i += 1)(hiresVO = new HiresVO(dest, files[i].fileName)).type = files[i].vs, hiresVO.replace = !0, result.hiresOnFS.push(hiresVO) - } - }; - return result -}]), app.service("SearchModel", ["$rootScope", function($rootScope) { - var result = { - allowInfiniteScroll: !1, - searchResultItems: [], - numOfResults: 0, - onSearch: function(data) { - result.searchResultVO = new ItemsVO(data.commands[0]), result.numOfResults = data.commands[0].nbr_footage + data.commands[0].nbr_music + data.commands[0].nbr_sfx + data.commands[0].nbr_ae, console.log("SearchModel onSearch num of results: ", result.numOfResults), "replace" === result.resultType && (result.searchResultItems = [], window.scrollTo(0, 0), 0 === result.numOfResults ? $rootScope.$emit("message view requested", !0, NO_RESULTS, !0, NO_RESULTS_ICON) : $rootScope.$emit("message view requested", !1)); - for (var i = 0; i < result.searchResultVO.items.length; i++) result.searchResultItems.push(result.searchResultVO.items[i]); - result.isSearching = !1, resizePanel() - }, - sumOfBitmasks: "", - query: "", - filter: "1", - resultType: "replace", - page: 0, - isSearching: !1, - filteredItems: [], - fps: "", - fpsgt: "", - res: "", - pricegt: "", - pricelt: "", - durationgt: "", - durationlt: "" - }; - return result -}]), app.factory("UserModel", [function() { - var firstTimeUser = !0, - user = { - onUserInfo: function(data) { - user.setCredits(data.credit), user.setUserName(data.un), user.setFirstName(data.fn), user.setLastName(data.ln), user.setAvatarURL(data.icon_base, data.av) - }, - setCredits: function(num) { - user.credits = num - }, - getCredits: function() { - return user.credits - }, - setUID: function(uid) { - user.uid = uid - }, - getUID: function() { - return user.uid - }, - setCM: function(cm) { - user.cm = cm - }, - getCM: function() { - return user.cm - }, - setCX: function(cx) { - user.cx = cx - }, - getCX: function() { - return user.cx - }, - setUserName: function(name) { - user.userName = name - }, - getUserName: function() { - return user.userName - }, - setFirstName: function(name) { - user.firstName = name - }, - getFirstName: function() { - return user.firstName - }, - setLastName: function(name) { - user.lastName = name - }, - getLastName: function() { - return user.lastName - }, - setAvatarURL: function(base, url) { - user.avatarURL = base + url - }, - getAvatarURL: function() { - return user.avatarURL - }, - setFirstTimeUser: function(state) { - firstTimeUser = state - }, - getFirstTimeUser: function() { - return firstTimeUser - } - }; - return user -}]), app.factory("VersionsModel", ["$rootScope", function($rootScope) { - var result = { - versions: [], - setVersions: function(v) { - result.versions = []; - for (var i = 0; i < v.length; i++) result.versions[i] = v[i]; - $rootScope.$emit("on versions selected", result.versions) - }, - getVersions: function() { - return result.versions - } - }; - return result -}]), app.factory("ViewStateModel", ["$rootScope", "SearchModel", function($rootScope, SearchModel) { - var state; - return { - allowPreviews: !1, - setState: function(s) { - state = s, SearchModel.allowInfiniteScroll = "search" === state || ($rootScope.$emit("filters button clicked", !1), !1) - }, - getState: function() { - return state - } - } -}]), app.service("AnalyticsService", ["$http", "$rootScope", "UserModel", "CartModel", function($http, $rootScope, UserModel, CartModel) { - var result = { - sendData: function(data, type) { - GA_TRACKING_CODE, - UserModel.getUID(), - UserModel.getUID(), - HOST_NAME, - PLUGIN_VERSION - }, - send: function(payload) { - $http({ - method: "POST", - url: payload - }).then(function(response) { - console.log("AnalyticsService then: ", response) - }, function(response) { - console.log("AnalyticsService error: ", response) - }) - } - }; - return result -}]), app.service("Service", ["$rootScope", "APIService", "LoginModel", "UserModel", "SearchModel", "FreebiesModel", "BinsModel", "ViewStateModel", "DownloadModel", "CheckOutModel", "PreviewsModel", "ReplaceModel", "ViewStateService", "ImportedPreviewsService", "AnalyticsService", "UserService", "BillingInfoModel", function($rootScope, APIService, LoginModel, UserModel, SearchModel, FreebiesModel, BinsModel, ViewStateModel, DownloadModel, CheckOutModel, PreviewsModel, ReplaceModel, ViewStateService, ImportedPreviewsService, AnalyticsService, UserService, BillingInfoModel) { - $rootScope.$on("api call", function(event, apiObj) { - call[apiObj.fn](sortArgs(apiObj.args)) - }); - var call = { - login: function() { - var obj = [{ - command: "login", - username: arguments[0][0], - password: arguments[0][1] - }]; - APIService.call(obj).then(function(data) { - LoginModel.setLoggedIn(!0), LoginModel.setCX(data.commands[0].cx), LoginModel.setCM(data.commands[0].cm), UserService.saveData(data.commands[0].cx, data.commands[0].cm), call.getUserInfo() - }).catch(function(err) {}) - }, - logout: function() { - console.log("Service logout"); - APIService.call([{ - command: "logout" - }]).then(function(data) { - LoginModel.setLoggedIn(!1) - }).catch(function(err) {}) - }, - getUserInfo: function() { - APIService.call([{ - command: "userinfo" - }]).then(function(data) { - "" != data.commands[0].uid && (UserModel.onUserInfo(data.commands[0]), call.getBins(), setTimeout(function() { - call.getCart() - }, 1e3), call.getActiveBin(), call.getBillingAddresses(), LoginModel.getLoggedIn() || LoginModel.setLoggedIn(!0)) - }).catch(function(err) {}) - }, - search: function() { - var obj = [{ - command: "search", - query: SearchModel.query + SearchModel.res + SearchModel.fps + SearchModel.fpsgt + SearchModel.pricegt + SearchModel.pricelt + SearchModel.durationgt + SearchModel.durationlt, - sb: SearchModel.filter, - bm: SearchModel.sumOfBitmasks, - no: "25", - p: SearchModel.page, - col: "1523" - }]; - APIService.call(obj).then(function(data) { - SearchModel.onSearch(data), ViewStateModel.allowPreviews = !0 - }).catch(function(err) {}) - }, - getFreeClips: function() { - APIService.call([{ - command: "get_free_clips" - }]).then(function(data) { - FreebiesModel.onFreebies(data) - }).catch(function(err) {}) - }, - getCart: function() { - APIService.call([{ - command: "get_cart_formatted", - artistinfo: "1" - }]).then(function(data) { - console.log("Service getCart data", data), $rootScope.$emit("on cart", data) - }).catch(function(err) {}) - }, - getCartTotal: function() { - var obj = [{ - command: "get_cart_total", - addressid: BillingInfoModel.getDefaultInfo() ? BillingInfoModel.getDefaultInfo().addressid : "", - use_credits: "1" - }]; - APIService.call(obj).then(function(data) { - $rootScope.$emit("on cart total", data) - }).catch(function(err) {}) - }, - getBillingAddresses: function(setState) { - APIService.call([{ - command: "get_billing_addresses" - }]).then(function(data) { - BillingInfoModel.onBillingInfo(data), setState && $rootScope.$emit("on modal choose billing info requested"), call.getCartTotal() - }).catch(function(err) {}) - }, - setBillingAddress: function(info) { - console.log("Service setBillingAddresses obj:", info); - var data = info[0]; - data.addressID || (data.addressID = ""); - var obj = [{ - command: "set_billing_address", - country: data.country, - addressid: data.addressID, - first_name: data.firstName, - last_name: data.lastName, - company_name: data.organization, - company_department: data.department, - company_id: data.companyID, - vat_id: data.vatID, - street1: data.street1, - street2: data.street2, - city: data.city, - state: data.state, - province: data.province, - postal_code: data.zipCode - }]; - APIService.call(obj).then(function(data) { - call.getBillingAddresses(!0) - }).catch(function(err) {}) - }, - getBins: function() { - APIService.call([{ - command: "get_bins" - }]).then(function(data) { - BinsModel.onBins(data) - }).catch(function(err) {}) - }, - getActiveBin: function() { - APIService.call([{ - command: "get_active_bin" - }]).then(function(data) { - BinsModel.onActiveBin(data) - }).catch(function(err) {}) - }, - setActiveBin: function(id) { - var obj = [{ - command: "set_active_bin", - binid: id - }]; - APIService.call(obj).then(function(data) { - setTimeout(function() { - call.getActiveBin() - }, 1e3) - }).catch(function(err) {}) - }, - getBin: function() { - var obj = [{ - command: "get_bin_formatted", - binid: BinsModel.showBin.id - }]; - APIService.call(obj).then(function(data) { - BinsModel.onBin(data) - }).catch(function(err) {}) - }, - modifyBin: function(binID, addID, rmID) { - var obj = [{ - command: "modify_active_bin", - binid: binID, - addid: addID, - rmid: rmID - }]; - APIService.call(obj).then(function(data) { - "1" == data.commands[0].nbr_removed ? call.getBin(BinsModel.binVO.id) : $rootScope.$emit("added to bin") - }).catch(function(err) {}) - }, - createBin: function(binName) { - var obj = [{ - command: "create_bin", - name: binName - }]; - APIService.call(obj).then(function(data) { - BinsModel.newBinName; - call.setActiveBin(data.commands[0].binid), call.getBins() - }).catch(function(err) {}) - }, - removeBin: function(id) { - var obj = [{ - command: "delete_bin", - binid: id - }]; - APIService.call(obj).then(function(data) { - call.getBins(), $rootScope.$emit("collection removed", data) - }).catch(function(err) {}) - }, - getPurchases: function() { - APIService.call([{ - command: "get_downloads_formatted" - }]).then(function(data) { - console.log("Service getPurchases data", data), $rootScope.$emit("on purchases", data) - }).catch(function(err) {}) - }, - getPurchaseURL: function(itemID, transactionID, versionID, version) { - console.log("Service getPurchaseURL", itemID, transactionID, versionID, version); - var obj = [{ - command: "download", - bid: itemID, - tr: transactionID, - v: versionID, - bitoffset: version - }]; - APIService.call(obj).then(function(data) { - console.log("Service getPurchaseURL data", data), DownloadModel.downloadingBatchURLs ? DownloadModel.onGetAllPurchaseURLs(data) : DownloadModel.onGetPurchaseURL(data) - }).catch(function(err) {}) - }, - modifyCart: function() { - var obj = [{ - command: "modify_active_cart", - addid: arguments[0][0], - rmid: arguments[0][1] - }]; - APIService.call(obj).then(function(data) { - 1 === data.commands[0].nbr_added && $rootScope.$emit("added to cart"), call.getCart(), call.getCartTotal() - }).catch(function(err) {}) - }, - purchaseWithCredits: function(buyAnyway, userData) { - var obj = [{ - command: "purchase_using_credits", - override: buyAnyway, - userdata: userData, - addressid: BillingInfoModel.getDefaultInfo().addressid - }]; - APIService.call(obj).then(function(data) { - console.log("purchaseWithCredits data", data), ReplaceModel.getState() === DEFAULT && $rootScope.$emit("modal simple requested", ["Your purchase has been successful!", "Your items are now ready to download."]), $rootScope.$emit("purchase complete"), ReplaceModel.getState() === NOT_PURCHASED ? call.getPurchases() : ViewStateService.viewRequested("downloads"), call.getUserInfo() - }).catch(function(err) {}) - }, - purchaseWithCash: function(buyAnyway, userData) { - var obj = [{ - command: "purchase_using_cash", - AdobePremierePlugin: "html", - override: buyAnyway, - userdata: userData, - addressid: BillingInfoModel.getDefaultInfo().addressid, - use_credits: "1" - }]; - APIService.call(obj).then(function(data) { - console.log("Service purchaseWithCash data", data), CheckOutModel.onPurchase(data) - }).catch(function(err) {}) - }, - promoRedeem: function(code) { - var obj = [{ - command: "promo_redeem", - promocode: code - }]; - APIService.call(obj).then(function(data) { - call.getUserInfo(), $rootScope.$emit("promo code added", data) - }).catch(function(err) {}) - }, - getImportedPreviews: function() { - console.log("Service getImportedPreviews", ImportedPreviewsService.idsString); - var obj = [{ - command: "get_clip_data_array", - itemids: ImportedPreviewsService.idsString, - col: "1523", - verboselvl: "100" - }]; - APIService.call(obj).then(function(data) { - PreviewsModel.onPreviews(data) - }).catch(function(err) {}) - }, - getFormats: function(item) { - console.log("Service getFormats", item.id); - var obj = [{ - command: "get_versions_formatted", - vm: item.id - }]; - APIService.call(obj).then(function(data) { - console.log("Service getFormats data", data); - var formats = data.commands[0].items; - $rootScope.$emit("formats complete", item, formats) - }).catch(function(err) {}) - }, - getFormatsReplacing: function(item) { - console.log("Service getFormatsReplacing", item.id); - var obj = [{ - command: "get_versions_formatted", - vm: item.id - }]; - APIService.call(obj).then(function(data) { - console.log("Service getFormatsReplacing data", data); - var formats = data.commands[0].items; - $rootScope.$emit("formats replacing complete", item, formats) - }).catch(function(err) {}) - }, - getMissingItems: function(itemIDsString) { - console.log("Service getMissingItems itemIDsString", itemIDsString); - var obj = [{ - command: "get_clip_data_array", - itemids: itemIDsString, - col: "1523", - verboselvl: "100" - }]; - APIService.call(obj).then(function(data) { - ReplaceModel.setState(MISSING_ITEMS), console.log("Service getMissingItems data", data), $rootScope.$emit("missing items complete", data) - }).catch(function(err) {}) - } - }; - return call -}]), app.factory("APIService", ["$http", "ViewStateModel", "LoginModel", function($http, ViewStateModel, LoginModel) { - return { - call: function(data) { - ViewStateModel.allowPreviews = !1; - var url, secret, apiKey, _0xf310 = ["test", "https://test.pond5.com/?page=api", "live", "https://www.pond5.com/?page=api", "oi23Jan3Inwh2io", "220655_769351580"]; - MODE === _0xf310[0] ? API_URL = _0xf310[1] : MODE === _0xf310[2] && (API_URL = _0xf310[3]), API_SECRET = _0xf310[4], API_KEY = _0xf310[5], url = API_URL, secret = API_SECRET, apiKey = API_KEY; - var stringified = JSON.stringify(data), - md5target = stringified + secret + "dragspel", - md5tostring = CryptoJS.MD5(md5target).toString(), - cx = LoginModel.getCX(), - cm = LoginModel.getCM(), - dataObj = { - api_key: apiKey, - commands_json: stringified, - commands_hash: md5tostring, - ver: 1, - https: 1 - }, - jsnstr = JSON.stringify(dataObj); - return $http({ - url: url, - method: "POST", - data: "api=" + jsnstr + "&apicx=" + cx + "&apicm=" + cm, - headers: { - "Content-Type": "application/x-www-form-urlencoded" - } - }).then(function(result) { - return ViewStateModel.allowPreviews = !0, result.data - }) - } - } -}]), app.factory("myHttpInterceptor", ["$q", "$rootScope", "ViewStateModel", function($q, $rootScope, ViewStateModel) { - return { - response: function(response) { - var errorFree = !0; - return "POST" === response.config.method && (response.data.e ? (console.log("Apiservice myHttpInterceptor error >>>", response.data), errorFree = !1) : response.data.commands && response.data.commands.forEach(function(entry) { - if (entry && entry.hasOwnProperty("e")) { - if (response.config.data && -1 != response.config.data.indexOf("userinfo")) console.log("myHttpInterceptor user info, do not show alert ", response); - else if (103 === response.data.commands[0].c) response.data.commands[0].a && (console.log("APIService myHttpInterceptor alreadyBought or onwClips", response.data.commands[0].a), 0 < response.data.commands[0].a.bought_before.length && ($rootScope.$emit("alreadyBought", response.data.commands[0].a.bought_before), console.log("APIService myHttpInterceptor alreadyBought", response.data.commands[0].a.bought_before)), 0 < response.data.commands[0].a.ownClips.length && ($rootScope.$emit("ownClips", response.data.commands[0].a.ownClips), console.log("APIService myHttpInterceptor ownClips", response.data.commands[0].a.ownClips))); - else { - console.log("myHttpInterceptor modal simple requested :", entry), "You are not logged in" == entry.s.split(": ")[1] ? $rootScope.$emit("modal not logged in", [ERROR]) : $rootScope.$emit("modal simple requested", [ERROR, entry.s.split(": ")[1]]) - } - errorFree = !1 - } - })), errorFree ? response : $q.reject(response) - }, - responseError: function(response) { - return response.config.url == MODAL_INTRO_HTML || response.config.url == MODAL_CHOOSE_BILLING_INFO_HTML ? console.log("apiService don't show error modal for ", response.config.url) : ($rootScope.$emit("modal simple requested", [ERROR, response.headers().status]), console.log("apiService don't show error modal but response ", response)), $q.reject(response) - } - } -}]), app.config(function($httpProvider) { - $httpProvider.interceptors.push("myHttpInterceptor") -}), app.service("CheckOutService", ["CartModel", "UserModel", "Service", function(CartModel, UserModel, Service) { - this.onCheckOutRequested = function(buyAnyway) { - console.log("CheckOutService total before VAT: ", CartModel.cartTotal.subtotals.afterVat), console.log("CheckOutService credits: ", CartModel.cartTotal.creditsData.availableSum), console.log("CheckOutService buyAnyway: ", buyAnyway), CartModel.cartTotal.creditsData.availableSum < CartModel.cartTotal.subtotals.afterVat ? Service.purchaseWithCash(buyAnyway) : Service.purchaseWithCredits(buyAnyway) - } -}]), app.service("CreateOnFileSystemService", ["AppModel", "CreateFileCompleteService", function(AppModel, CreateFileCompleteService) { - var call = { - createUserHomeFolder: function() { - call.createDir(AppModel.getDirHomePond5()) - }, - createUserSubFolders: function() { - console.log("CreateOnFileSystemService createUserSubFolders", AppModel.getDirDefaultLib()); - for (var dirs = [AppModel.getDirImports(), AppModel.getDirPrefs(), AppModel.getDirDefaultLib(), AppModel.getDirDestinations(), AppModel.getDirUser()], i = 0; i < dirs.length; i++) { - var dir = dirs[i]; - call.createDir(dir) - } - }, - createDestinationBaseFolder: function() { - call.createDir(AppModel.currentBaseFolder + path.sep + "pond5", !0) - }, - createDestinationFolders: function() { - AppModel.previewsDir = AppModel.currentBaseFolder + path.sep + "pond5" + path.sep + "previews", AppModel.purchasedDir = AppModel.currentBaseFolder + path.sep + "pond5" + path.sep + "purchased", call.createDir(AppModel.previewsDir), call.createDir(AppModel.purchasedDir) - }, - createDir: function(dir, isDestination) { - fs.exists(dir, function(exists) { - exists ? call.onDirReady(dir, isDestination) : fs.mkdir(dir, 511, function(err) { - if (err) throw err; - call.onDirReady(dir, isDestination) - }) - }) - }, - onDirReady: function(dir, isDestination) { - if (isDestination = isDestination || !1) this.createDestinationFolders(); - else { - var filePath, xml; - switch (dir) { - case AppModel.getDirHomePond5(): - call.createUserSubFolders(); - break; - case AppModel.getDirImports(): - filePath = "imported_previews.xml", xml = ''; - break; - case AppModel.getDirPrefs(): - filePath = "preferences.xml", xml = ''; - break; - case AppModel.getDirUser(): - filePath = "user.xml", xml = ''; - break; - case AppModel.getDirDestinations(): - filePath = "destinations.xml", xml = ''; - break; - case AppModel.getDirDefaultLib(): - filePath = "defaultLib.xml", xml = ''; - break; - case AppModel.currentBaseFolder: - this.createDestinationFolders(); - break; - default: - return - } - filePath && call.createFile(dir + path.sep + filePath, '' + xml) - } - }, - createFile: function(file, content) { - fs.exists(file, function(exists) { - exists ? CreateFileCompleteService.onFileReady(file) : fs.writeFile(file, content, function(err) { - if (err) throw err; - console.log("CreateOnFileSystemService, created file: ", file), CreateFileCompleteService.onFileReady(file) - }) - }) - } - }; - return call -}]), app.service("DeleteOnFileSystemService", [function() { - return { - deleteFiles: function(items) { - items.forEach(function(item) { - var file = item.downloadDestination + item.fileName; - fs.exists(file, function(exists) { - exists && fs.unlink(file, function(err) { - if (err) throw err - }) - }) - }) - }, - deleteFolder: function(folders, cb) { - console.log("DeleteOnFileSystemService deleteFolder, folders, length:", folders.length), folders.forEach(function(folder) { - console.log("DeleteOnFileSystemService deleteFolder, folder:", folder), fs.exists(folder, function(exists) { - exists ? rimraf(folder, function(err) { - if (err) throw err; - console.log("DeleteOnFileSystemService deleteFolder deleted: ", folder), cb() - }) : (console.log("DeleteOnFileSystemService deleteFile folder does not exist:", folder), cb()) - }) - }) - } - } -}]), app.factory("DownloadBatchService", ["Service", "PurchasesModel", "DownloadModel", function(Service, PurchasesModel, DownloadModel) { - return { - onBatchRequested: function(purchases) { - var j, i; - for (purchases = purchases || PurchasesModel.purchasesVO.items, i = 0; i < purchases.length; i += 1) - for (j = 0; j < PurchasesModel.purchasesVO.items.length; j += 1) purchases[i].id == PurchasesModel.purchasesVO.items[j].id && (purchases[i] = PurchasesModel.purchasesVO.items[j]); - for (DownloadModel.downloadingBatchURLs = !0, purchases = purchases.filter(function(v, i, a) { - return a.indexOf(v) == i - }), i = 0; i < purchases.length; i += 1) Service.getPurchaseURL(purchases[i].id, purchases[i].transactionID, purchases[i].versionID, purchases[i].version) - } - } -}]), app.service("DownloadCancelService", ["$rootScope", "DeleteOnFileSystemService", "ProgressService", "DownloadModel", function($rootScope, DeleteOnFileSystemService, ProgressService, DownloadModel) { - return { - onCancelSingle: function(item) { - console.log("DownloadCancelService onCancelSingle: ", item, item.downloadType), item.canceled = !0, $rootScope.$emit("cancel download", item), ProgressService.clearItem(item), DeleteOnFileSystemService.deleteFiles([item]), item.downloading && (item.downloading = !1, DownloadModel.downloadCounter--); - for (var len = DownloadModel.itemsDownloadList.length; len--;) - if (DownloadModel.itemsDownloadList[len].fileName === item.fileName) { - var removal = DownloadModel.itemsDownloadList[len]; - DownloadModel.itemsDownloadList = DownloadModel.itemsDownloadList.filter(function(itm) { - return itm !== removal - }) - } console.log("DownloadCancelService onCancelSingle num of items: ", DownloadModel.itemsDownloadList.length), $rootScope.$emit("modal simple requested", ["", "Download of " + item.fileName + " has been canceled."], "sm") - }, - onCancelAll: function() { - console.log("DownloadCancelService cancel all downloads", DownloadModel.itemsDownloadList); - for (var len = DownloadModel.itemsDownloadList.length; len--;) { - var item = DownloadModel.itemsDownloadList[len]; - 100 !== item.progressPerc && (item.canceled = !0, $rootScope.$emit("cancel download", item), ProgressService.clearItem(item), DeleteOnFileSystemService.deleteFiles([item])) - } - $rootScope.$emit("modal simple requested", ["", "All incomplete downloads have been canceled and deleted."], "sm"), DownloadModel.downloadCounter = -1, DownloadModel.itemsDownloadList = [] - } - } -}]), app.service("DownloadCompleteService", ["$rootScope", "UnzipService", function($rootScope, UnzipService) { - return { - onComplete: function(items) { - UnzipService.unzipItems(items) - } - } -}]), app.service("DownloadRequestService", ["$rootScope", "DownloadService", "ProgressService", "DownloadModel", "ReplaceModel", "AppModel", "ImportService", "ReplaceService", "StayAwakeService", "UnzipService", function($rootScope, DownloadService, ProgressService, DownloadModel, ReplaceModel, AppModel, ImportService, ReplaceService, StayAwakeService, UnzipService) { - $rootScope.$on("download requested", function(event, items) { - var downloadFolderName; - console.log("DownloadRequestService DownloadModel.itemsDownloadList: ", DownloadModel.itemsDownloadList), "preview" === items[0].downloadType ? downloadFolderName = "previews" : "purchase" === items[0].downloadType && (downloadFolderName = "purchased"); - var item, dest = AppModel.currentBaseFolder + path.sep + "pond5" + path.sep + downloadFolderName + path.sep; - console.log("DownloadRequestService downloadRequested items:", items), $rootScope.$emit("scroll progress to top"); - for (var i = 0; i < items.length; i++) { - var codec; - (item = items[i]).downloadDestination = dest, "preview" === item.downloadType ? "Video" == item.type || "AE" == item.type ? item.downloadURL = item.h264URL : "Sound effect" == item.type || "Music" == item.type ? item.downloadURL = item.m4aURL : "Photo" != item.type && "Illustration" != item.type || (item.downloadURL = item.iconLargeURL) : "purchase" === item.downloadType && (item.downloadURL = item.hiresURL), "Photo" == item.type ? item.ext = "jpg" : item.ext = item.downloadURL.substr(item.downloadURL.lastIndexOf(".") + 1).split("?")[0], item.videoCodec && (codec = item.videoCodec), "preview" !== item.downloadType && "unknown" !== codec && void 0 !== codec || (codec = ""), item.fileName = getFormattedName(item.id + " " + codec + " " + item.name + "." + item.ext), item.progressName = getAbbrName(item.fileName, 20), "preview" === item.downloadType && "AE" === item.vs && (item.fileName = "AE " + item.fileName), "purchase" === item.downloadType && ("AE" === item.vs ? item.fileName = "AE " + item.fileName : item.fileName = "hires " + item.fileName), $rootScope.$emit("open progress", !1), item.progressPerc = "", item.progressMB = "", ProgressService.addItem(item) - } - $rootScope.$$listenerCount["on item downloaded"] || $rootScope.$on("on item downloaded", function(event) { - DownloadModel.downloadCounter++, console.log("DownloadRequestService on item downloaded DownloadModel.downloadCounter: ", DownloadModel.downloadCounter), console.log("DownloadRequestService on item downloaded DownloadModel.itemsDownloadList: ", DownloadModel.itemsDownloadList); - var item = DownloadModel.itemsDownloadList[DownloadModel.downloadCounter]; - if (item) { - StayAwakeService.updateState(!0); - new DownloadService.download(item) - } else if (StayAwakeService.updateState(!1), DownloadModel.downloadCounter--, console.log("DownloadRequestService download complete, check if something needs to be done, complete previews", ProgressService.getCompletedPreviews()), ProgressService.getCompletedPreviewsStatus() && ImportService.importClips(ProgressService.getCompletedPreviews()), ProgressService.getCompletedPurchasesStatus()) { - console.log("DownloadRequestService purchases completed: ", ProgressService.getCompletedPurchases()), console.log("DownloadRequestService purchases completed ReplaceModel.getState(): ", ReplaceModel.getState()); - var AEItems = []; - if (ProgressService.getCompletedPurchases().forEach(function(item) { - "AE" == item.type && AEItems.push(item) - }), "1.0.8" != PLUGIN_VERSION && UnzipService.unzipItems(AEItems), ReplaceModel.getState() === NOT_DOWNLOADED) { - var dest = AppModel.currentBaseFolder + path.sep + "pond5" + path.sep + "purchased" + path.sep; - ProgressService.getCompletedPurchases().forEach(function(entry) { - ReplaceModel.addHires(dest, [entry]) - }), ReplaceService.onPurchasedAndDownloaded(AEItems.length) - } - } - }), console.log("DownloadRequestService new request, ProgressService.getIncompleteItems ", ProgressService.getIncompleteItems()), 0 < ProgressService.getIncompleteItems().length && !ProgressService.getDownloadingStatus() && $rootScope.$emit("on item downloaded") - }) -}]), app.service("DownloadService", ["$rootScope", "ProgressService", function($rootScope, ProgressService) { - function download(item) { - console.log("DownloadService download item: ", item); - var allowWriting = !0; - $rootScope.$on("cancel download", function(event, itm) { - itm.fileName === item.fileName && (itm.canceled = !0, item.canceled = !0, allowWriting = !1) - }), item.downloading = !0; - var file, sizeOnFS, writeOptions, path = item.downloadDestination + item.fileName; - writeOptions = fs.existsSync(path) ? (sizeOnFS = fs.statSync(path).size, console.log("DownloadService sizeOnFS: ", sizeOnFS), { - flags: "r+" - }) : (console.log("DownloadService file does not exist yet, create stream"), { - flags: "w" - }), file = fs.createWriteStream(path, writeOptions), https.get(item.downloadURL, function(res) { - var len; - res.headers["content-length"] ? (len = parseInt(res.headers["content-length"], 10), console.log("DownloadService res has content-length: ", res)) : console.log("DownloadService content-length unknown", res); - var progressPerc, cur = 0, - total = len / 1048576; - - function setToComplete() { - item.canceled || (item.progressPerc = 100, item.progressMB = total.toFixed(2) + "/" + total.toFixed(2) + "MB", item.completed = !0), item.canceled = !1, item.downloading = !1, $rootScope.$emit("on item downloaded"), $rootScope.$digest() - } - res.pipe(file), len <= sizeOnFS && (file.end(), setToComplete()), res.on("data", function(chunk) { - allowWriting ? (cur += chunk.length, progressPerc = (100 * cur / len).toFixed(2), $rootScope.$apply(function() { - item.progressPerc = progressPerc.split(".")[0], item.progressMB = (cur / 1048576).toFixed(2) + "/" + total.toFixed(2) + "MB" - })) : res.destroy() - }).on("error", function(e) { - console.log("DownloadService error: " + e.message) - }).on("end", function() { - file.end(), setToComplete() - }) - }).on("error", function(err) { - console.error("Download Error code and filename:", err.code, item.fileName), console.error("Download err:", err), item.progressPerc = 0, item.progressMB = "", setTimeout(function() { - download(item, options) - }, 1e3) - }) - } - return { - download: function(item, options) { - return new download(item, options) - } - } -}]), app.service("ImportAEService", ["$rootScope", "ReplaceModel", function($rootScope, ReplaceModel) { - var call = { - showingModal: !1, - import: function(sourceDir) { - var walk = function(dir, done) { - var files = []; - fs.readdir(dir, function(err, list) { - if (err) return done(err); - var i = 0; - ! function next() { - var file = list[i++]; - if (!file) return done(null, files); - file = dir + "/" + file, fs.stat(file, function(err, stat) { - stat && stat.isDirectory() ? walk(file, function(err, res) { - files = files.concat(res), next() - }) : (files.push(file), next()) - }) - }() - }) - }; - walk(sourceDir, function(err, files) { - if (err) throw err; - for (var i = 0; i < files.length; i += 1) console.log("ImportService file", files[i]), -1 != files[i].indexOf(".aep") && csInterface.evalScript("importAETemplate(" + JSON.stringify(files[i]) + ")", function(result) { - call.showingModal || ($rootScope.$emit("modal simple requested", ["", "Your project has been updated."]), call.showingModal = !0), console.log("ImportAEService import showingModal", call.showingModal) - }) - }) - } - }; - return call -}]), app.factory("ImportedPreviewsService", ["$rootScope", function($rootScope) { - var result = { - readXML: function() { - var dest = path.sep + "pond5" + path.sep + "imports" + path.sep + "imported_previews.xml"; - result.file = getUserHome() + dest, fs.readFile(result.file, "utf8", function(err, data) { - if (err) throw err; - result.xml = data, result.parseXML() - }) - }, - saveItem: function(id) { - var idsString = result.idsString.toString(); - 1 == idsString.indexOf(id.toString()) && (0 < idsString.length ? result.idsString += "," + id : result.idsString = id, result.writeToDisk()) - }, - deleteItem: function(id) { - -1 != result.idsString.indexOf(id) && (result.idsString = result.idsString.replace(id, "")), "," == result.idsString.substr(0, 1) && (result.idsString = result.idsString.substr(1)), "," == result.idsString.substr(result.idsString.length - 1, result.idsString.length) && (result.idsString = result.idsString.slice(0, -1)), result.writeToDisk(), $rootScope.$emit("api call", { - fn: "getImportedPreviews" - }) - }, - parseXML: function() { - var parser = new xml2js.Parser; - parser.addListener("end", function(res) { - (result.parsedXML = res) && (result.idsString = res.root.previews[0].$.ids) - }), parser.parseString(result.xml) - }, - writeToDisk: function() { - result.parsedXML.root.previews[0].$.ids = result.idsString; - var xml = (new xml2js.Builder).buildObject(result.parsedXML); - fs.writeFile(result.file, xml, function(err) { - if (err) throw err - }) - } - }; - return result -}]), app.service("MissingItemsService", ["$rootScope", "MissingItemsModel", "ReplaceModel", "Service", "CartModel", "ReplaceServiceShared", function($rootScope, MissingItemsModel, ReplaceModel, Service, CartModel, ReplaceServiceShared) { - $rootScope.$on("missing items complete", function(event, items) { - console.log("MissingItemsService on missing items: ", items), ReplaceModel.getState() === MISSING_ITEMS && result.onMissingItems(items) - }), $rootScope.$on("formats replacing complete", function(event, item, formats) { - ReplaceModel.getState() === MISSING_ITEMS && result.onMissingItemsFormats(item, formats) - }), $rootScope.$on("on purchases vo", function(event, vo) { - console.log("MissingItemsService on purchases vo, state: ", ReplaceModel.getState()), ReplaceModel.getState() != DEFAULT && result.onPurchasesVO(vo) - }); - var result = { - missingItemsCounter: 0, - onMissingItems: function(data) { - var missingItemsVO = new MissingItemsVO(data.commands[0]); - (MissingItemsModel.missingItemsVO = missingItemsVO).items.forEach(function(entry) { - Service.getFormatsReplacing(entry) - }) - }, - onMissingItemsFormats: function(item, formats) { - if (result.missingItemsCounter++, 1 < (formats = _.uniq(formats, function(p) { - return p.ti - })).length) - for (i = 0; i < formats.length; i++) item.formats[i] = new ItemVO(formats[i]), item.parentFormatID = item.id, item.formats[i].offset = formats[i].offset; - result.missingItemsCounter === MissingItemsModel.missingItemsVO.items.length && (result.missingItemsCounter = 0, Service.getPurchases()) - }, - onPurchasesVO: function(purchasesVO) { - for (var item, missingItems = MissingItemsModel.missingItemsVO.items, cartItems = CartModel.cartVO.items, purchasedItems = purchasesVO.items, i = 0; i < missingItems.length; i++) { - var cartItem, purchase; - item = missingItems[i]; - for (var j = 0; j < cartItems.length; j++) { - cartItem = cartItems[j], item.id == cartItem.id && (item.inCart = !0); - for (var formats = item.formats, k = 0; k < formats.length; k++) formats[k].id == cartItem.id && formats[k].offset == cartItem.offset && (formats[k].inCart = !0, item.inCart = !0) - } - for (j = 0; j < purchasedItems.length; j++) { - purchase = purchasedItems[j], item.id == purchase.id && (item.inDownloads = !0, item.transactionID = purchase.transactionID); - for (formats = item.formats, k = 0; k < formats.length; k++) formats[k].id == purchase.id && (formats[k].inDownloads = !0, formats[k].transactionID = purchase.transactionID, purchasedItems[j].parentFormatID && (formats[k].parentFormatID = purchase.parentFormatID)) - } - } - ReplaceModel.getState() === MISSING_ITEMS ? $rootScope.$emit("modal replace", missingItems) : ReplaceModel.getState() === NOT_PURCHASED && ReplaceServiceShared.onPurchased(missingItems) - } - }; - return result -}]), app.service("ProgressService", ["$rootScope", "DownloadModel", function($rootScope, DownloadModel) { - var result = { - alreadyHasItem: function(item) { - var itemsContainItem = !1; - return DownloadModel.itemsDownloadList.forEach(function(entry) { - entry.fileName === item.fileName && (itemsContainItem = !0) - }), itemsContainItem - }, - addItem: function(item) { - DownloadModel.itemsDownloadList.forEach(function(entry) { - entry.fileName === item.fileName && (console.log("ProgressService already in list: ", item.fileName), item.completed = !1, item.imported = !1, item.canceled = !1, item.progressPerc = 0, item.progressMB = "", DownloadModel.downloadCounter--, result.clearItem(item), console.log("ProgressService already in list, cleared: ", DownloadModel.itemsDownloadList)) - }), DownloadModel.itemsDownloadList.push(item), console.log("ProgressService addItem, list: ", DownloadModel.itemsDownloadList), $rootScope.$emit("added to progress") - }, - clearCompleteItems: function() { - console.log("ProgressService clearCompleteItems "); - for (var len = DownloadModel.itemsDownloadList.length, oldLen = len; len--;) { - var item = DownloadModel.itemsDownloadList[len]; - if (100 === item.progressPerc) { - item.completed = !1, item.imported = !1, item.canceled = !1, item.progressPerc = 0; - var removal = DownloadModel.itemsDownloadList[len]; - DownloadModel.itemsDownloadList = DownloadModel.itemsDownloadList.filter(function(itm) { - return itm !== removal - }) - } - } - var diff = oldLen - DownloadModel.itemsDownloadList.length; - DownloadModel.downloadCounter = DownloadModel.downloadCounter - diff, console.log("ProgressService clearCompleteItems DownloadModel.itemsDownloadList: ", DownloadModel.itemsDownloadList), console.log("ProgressService clearCompleteItems new downloadCounter: ", DownloadModel.downloadCounter), $rootScope.$emit("clear progress") - }, - clearIncompleteItems: function() { - console.log("ProgressService clearIncompleteItems "); - for (var len = DownloadModel.itemsDownloadList.length; len--;) - if (100 !== DownloadModel.itemsDownloadList[len].progressPerc) { - var removal = DownloadModel.itemsDownloadList[len]; - DownloadModel.itemsDownloadList = DownloadModel.itemsDownloadList.filter(function(itm) { - return itm !== removal - }) - } $rootScope.$emit("on clear", DownloadModel.itemsDownloadList) - }, - clearAllItems: function() { - console.log("ProgressService clearAllItems "), DownloadModel.itemsDownloadList = [], $rootScope.$emit("clear progress"), DownloadModel.downloadCounter = 0 - }, - clearItem: function(item) { - console.log("ProgressService clearItem "); - for (var len = DownloadModel.itemsDownloadList.length; len--;) - if (DownloadModel.itemsDownloadList[len].fileName === item.fileName) { - var removal = DownloadModel.itemsDownloadList[len]; - DownloadModel.itemsDownloadList = DownloadModel.itemsDownloadList.filter(function(itm) { - return itm !== removal - }) - } $rootScope.$emit("clear progress") - }, - getIncompleteItems: function() { - var incompletes = []; - return DownloadModel.itemsDownloadList.forEach(function(entry) { - entry.completed || (console.log("ProgressService not completed: ", entry.fileName), incompletes.push(entry)) - }), incompletes - }, - getCompletedPreviewsStatus: function() { - var allCompleted = !0; - return DownloadModel.itemsDownloadList.forEach(function(entry) { - entry.completed || "preview" !== entry.downloadType || (allCompleted = !1) - }), 0 === DownloadModel.itemsDownloadList.length && (allCompleted = !1), console.log("ProgressService getCompletedPreviewsStatus allCompleted", allCompleted), allCompleted - }, - getCompletedPreviews: function() { - var completes = []; - return DownloadModel.itemsDownloadList.forEach(function(entry) { - entry.completed && "preview" == entry.downloadType && completes.push(entry) - }), completes - }, - getCompletedPurchasesStatus: function() { - var allCompleted = !0; - return DownloadModel.itemsDownloadList.forEach(function(entry) { - entry.completed || "purchase" !== entry.downloadType || (allCompleted = !1) - }), 0 === DownloadModel.itemsDownloadList.length && (allCompleted = !1), console.log("ProgressService getCompletedPurchasesStatus allCompleted", allCompleted), allCompleted - }, - getCompletedPurchases: function() { - var completes = []; - return DownloadModel.itemsDownloadList.forEach(function(entry) { - entry.completed && "purchase" == entry.downloadType && completes.push(entry) - }), completes - }, - getDownloadingStatus: function() { - var downloading = !1; - return DownloadModel.itemsDownloadList.forEach(function(entry) { - entry.downloading && (downloading = !0) - }), downloading - } - }; - return result -}]), app.service("ReadClipsOnFSService", ["$rootScope", "ReplaceModel", "MissingItemsModel", "ViewStateService", "DownloadBatchService", "AppModel", function($rootScope, ReplaceModel, MissingItemsModel, ViewStateService, DownloadBatchService, AppModel) { - var call = { - listPurchasesOnFS: function(cb) { - ReplaceModel.hiresOnFS = []; - for (var cbCounter = 0, i = 0; i < AppModel.baseFolders.length; i++) call.readPurchasesFolders(AppModel.baseFolders[i] + path.sep + "pond5" + path.sep + "purchased" + path.sep, function() { - ++cbCounter === AppModel.baseFolders.length && (console.log("\nReadClipsOnFSService ReplaceModel.hiresOnFS done: ", cbCounter, ReplaceModel.hiresOnFS), call.listPreviewsOnFS(function() { - cb() - })) - }) - }, - readPurchasesFolders: function(dest, cb) { - fs.readdir(dest, function(err, files) { - if (err) throw new Error("ReadClipsOnFSService: " + dest + " does not exist."); - var hiresVO; - files = files.filter(junk.not); - for (var i = 0; i < files.length; i += 1) hiresVO = new HiresVO(dest, files[i]), ReplaceModel.hiresOnFS.push(hiresVO), 0 === path.extname(files[i]).length ? hiresVO.type = "AE folder" : ".zip" === path.extname(files[i]) ? hiresVO.type = "AE zip" : ".mov" === path.extname(files[i]) ? hiresVO.type = "video" : ".wav" === path.extname(files[i]) && (hiresVO.type = "audio"); - cb() - }) - }, - listPreviewsOnFS: function(cb) { - ReplaceModel.previewsOnFS = []; - for (var i = 0; i < AppModel.baseFolders.length; i++) { - var walk = function(dir, done) { - var files = []; - fs.readdir(dir, function(err, list) { - if (err) return done(err); - var i = 0; - ! function next() { - var file = list[i++]; - if (!file) return done(null, files); - file = dir + "/" + file, fs.stat(file, function(err, stat) { - stat && stat.isDirectory() ? walk(file, function(err, res) { - files = files.concat(res), next() - }) : (files.push(file), next()) - }) - }() - }) - }, - dest = AppModel.baseFolders[i] + path.sep + "pond5" + path.sep + "previews", - counter = 0; - walk(dest, function(err, files) { - if (err) throw err; - for (var previewVO, i = 0; i < files.length; i += 1) previewVO = new PreviewVO(dest, files[i]), ReplaceModel.previewsOnFS.push(previewVO); - ++counter === AppModel.baseFolders.length && cb() - }) - } - } - }; - return call -}]), app.service("ReplaceServiceShared", ["$rootScope", "ReplaceModel", "Service", "MissingItemsModel", "ViewStateService", "DownloadBatchService", "ImportAEService", "DeleteOnFileSystemService", function($rootScope, ReplaceModel, Service, MissingItemsModel, ViewStateService, DownloadBatchService, ImportAEService, DeleteOnFileSystemService) { - var call = { - removeDuplicates: function(clips) { - return clips = clips.filter(function(v, i, a) { - return a.indexOf(v) === i - }) - }, - getPreviewsOnFSNames: function() { - var previewNamesonFS = []; - return ReplaceModel.previewsOnFS.forEach(function(entry) { - previewNamesonFS.push(entry.name) - }), previewNamesonFS - }, - filterNonP5Clips: function(clips, previewNamesOnFS) { - return clips = clips.filter(function(n) { - return -1 != previewNamesOnFS.indexOf(n) - }) - }, - getPreviewsIDs: function(clips) { - var previewIDs = []; - return clips.forEach(function(entry) { - var substr = entry.split(" "); - "AE" === substr[0] ? previewIDs.push(substr[1]) : previewIDs.push(substr[0]) - }), console.log("\nReplaceServiceShared previewIDs: " + previewIDs), previewIDs - }, - setReplaceProp: function(ids) { - for (var i = 0; i < ids.length; i++) - for (var j = 0; j < ReplaceModel.hiresOnFS.length; j++) ids[i] === ReplaceModel.hiresOnFS[j].id && (ReplaceModel.hiresOnFS[j].replace = !0) - }, - getMissingItemIDs: function(clipsInSeqs) { - var clipsInSelectedSequences = clipsInSeqs; - console.log("ReplaceService ReplaceModel.aeItemsinProjectView: ", ReplaceModel.getAEItems()), 0 < ReplaceModel.getAEItems().length && (clipsInSelectedSequences = clipsInSelectedSequences.concat(ReplaceModel.getAEItems())), console.log("ReplaceService clips after concat layer items and AE items: ", clipsInSelectedSequences), clipsInSelectedSequences = call.removeDuplicates(clipsInSelectedSequences), console.log("\nReplaceServiceShared clipsInSelectedSequences after removing duplicates: ", clipsInSelectedSequences); - var previewNamesonFS = call.getPreviewsOnFSNames(); - console.log("\nReplaceServiceShared previewNamesonFS: ", previewNamesonFS), clipsInSelectedSequences = call.filterNonP5Clips(clipsInSelectedSequences, previewNamesonFS), console.log("\nReplaceServiceShared after filterNonP5Clips", clipsInSelectedSequences); - var previewIDs = call.getPreviewsIDs(clipsInSelectedSequences); - console.log("\nReplaceServiceShared previewIDs: " + previewIDs), call.setReplaceProp(previewIDs), console.log("\nReplaceServiceShared after set replace: " + ReplaceModel.hiresOnFS); - var hiresIDs = call.getHiresIDsonFS(); - console.log("\nReplaceServiceShared hiresIDs: " + hiresIDs); - var missingItemIDs = _(previewIDs).difference(hiresIDs), - missingIDsToString = missingItemIDs.join(","); - if (console.log("nReplaceServiceShared missingIDsToString: " + missingIDsToString), 0 < missingItemIDs.length) Service.getMissingItems(missingIDsToString); - else { - if (0 < hiresIDs.length) return hiresIDs.length; - 0 === clipsInSelectedSequences.length && (ReplaceModel.setState(DEFAULT), $rootScope.$emit("modal simple requested", ["", "There are no Pond5 previews in your current project."])) - } - }, - getHiresIDsonFS: function() { - var hiresIDs = []; - return ReplaceModel.hiresOnFS.forEach(function(entry) { - (entry.replace || entry.importAE) && hiresIDs.push(entry.id) - }), hiresIDs - }, - onModalReplaceOK: function() { - for (var item, missingItems = MissingItemsModel.missingItemsVO.items, itemsNotPurchased = [], itemsNotDownloaded = [], i = 0; i < missingItems.length; i++)(item = missingItems[i]).selected && !item.inDownloads && itemsNotPurchased.push(item), item.selected && item.inDownloads && itemsNotDownloaded.push(item); - 0 < itemsNotPurchased.length ? call.onNotPurchased(itemsNotPurchased) : 0 < itemsNotDownloaded.length ? (console.log("ReplaceServiceShared onModalReplaceOK, download items: ", itemsNotDownloaded), ReplaceModel.missingDownloads = itemsNotDownloaded, call.onNotDownloaded(itemsNotDownloaded)) : (ReplaceModel.setState(PURCHASED_AND_DOWNLOADED), console.log("ReplaceServiceShared onModalReplaceOK, replace"), call.onPurchasedAndDownloaded()) - }, - onNotPurchased: function(itemsNotPurchased) { - for (var addToCartItems = [], i = 0; i < itemsNotPurchased.length; i++) - if (item = itemsNotPurchased[i], 0 < itemsNotPurchased[i].formats.length) - for (var j = 0; j < itemsNotPurchased[i].formats.length; j++) format = itemsNotPurchased[i].formats[j], format.selected && (console.log("ReplaceServiceShared onNotPurchased add this format to cart: ", format), addToCartItems.push(format.id)); - else console.log("ReplaceServiceShared onNotPurchased add this item to cart: ", item), addToCartItems.push(item.id); - $rootScope.$emit("modal simple requested", ["", "Please review your Cart. Press the 'Checkout' button to proceed with replacing your previews."]); - var apiObj = { - fn: "modifyCart", - args: [addToCartItems.join(","), ""] - }; - $rootScope.$emit("api call", apiObj), ViewStateService.viewRequested("cart"), ReplaceModel.setState(NOT_PURCHASED) - }, - onPurchased: function(downloadItems) { - console.log("ReplaceServiceShared onPurchased: ", downloadItems); - for (var item, missingItems = MissingItemsModel.missingItemsVO.items, itemsNotDownloaded = [], i = 0; i < missingItems.length; i++)(item = missingItems[i]).inDownloads && itemsNotDownloaded.push(item); - 0 < itemsNotDownloaded.length && (console.log("ReplaceServiceShared onPurchased, download items: ", itemsNotDownloaded), ReplaceModel.missingDownloads = itemsNotDownloaded, $rootScope.$emit("modal simple requested", ["Your purchase has been successful.", "Your purchased clips will begin downloading now. Once the downloads are completed, your lo-res previews will be replaced with your high-res clips."]), call.onNotDownloaded(itemsNotDownloaded, !0)) - }, - onNotDownloaded: function(itemsNotDownloaded, afterPurchase) { - afterPurchase = afterPurchase || !1, console.log("ReplaceServiceShared onNotDownloaded missing items:", itemsNotDownloaded); - for (var downloadItems = [], i = 0; i < itemsNotDownloaded.length; i++) - if (item = itemsNotDownloaded[i], 0 < itemsNotDownloaded[i].formats.length) - for (var j = 0; j < itemsNotDownloaded[i].formats.length; j++) format = itemsNotDownloaded[i].formats[j], format.selected && (console.log("ReplaceServiceShared onNotDownloaded download this format: ", format), downloadItems.push(format)); - else console.log("ReplaceServiceShared onNotDownloaded download item: ", item), downloadItems.push(item); - afterPurchase || $rootScope.$emit("modal simple requested", ["You have purchases that are missing in your project. ", "They will be downloaded. Once the downloads are completed, your lo-res previews will be replaced with your high-res clips."]), DownloadBatchService.onBatchRequested(downloadItems), ReplaceModel.setState(NOT_DOWNLOADED) - } - }; - return call -}]), app.service("ScrollService", ["SearchModel", "Service", function(SearchModel, Service) { - this.onScroll = function() { - if (SearchModel.allowInfiniteScroll) { - var m = document.getElementById("main-holder"); - 1 === (getScroll()[1] - 72) / (m.scrollHeight - window.innerHeight) && (console.log("ScrollService show more: " + SearchModel.isSearching), SearchModel.isSearching || (SearchModel.isSearching = !0, SearchModel.resultType = "add", SearchModel.page = SearchModel.page + 1, Service.search())) - } - } -}]), app.factory("StartUpService", ["$rootScope", "CreateOnFileSystemService", "MissingItemsService", "ViewStateService", "AppModel", function($rootScope, CreateOnFileSystemService, MissingItemsService, ViewStateService, AppModel) { - return $("#logo").click(function() { - location.reload() - }), $rootScope.$on("environment set", function() { - console.log("StartUpService, 26/10 pointing at ", window.location.href), gup("tp", window.location.href) && (THIRD_PARTY = gup("tp", window.location.href)), -1 < window.location.href.indexOf("test") ? MODE = "test" : MODE = "live", console.log("StartUpService MODE:", MODE), console.log("StartUpService OS:", os.platform()), console.log("StartUpService, app version: ", PLUGIN_VERSION), AppModel.currentBaseFolder = AppModel.getDocumentsPath(), console.log("StartUpService currentBaseFolder: ", AppModel.currentBaseFolder + "\n\n"), CreateOnFileSystemService.createUserHomeFolder(), MissingItemsService.missingItemsCounter = 0, ViewStateService.viewRequested("search") - }), { - init: function() { - setTimeout(function() { - AppModel.setEnv() - }, 2e3) - } - } -}]), app.factory("StayAwakeService", ["$rootScope", "DownloadModel", function($rootScope, DownloadModel) { - return { - updateState: function(state) { - console.log("StayAwakeService state: ", state), state && !DownloadModel.stayAwake ? (sleep.prevent(), DownloadModel.stayAwake = !0) : !state && DownloadModel.stayAwake && (sleep.allow(), DownloadModel.stayAwake = !1) - } - } -}]), app.service("TransactionService", ["$q", "ViewStateService", "Service", "ReplaceModel", "AnalyticsService", "CartModel", function($q, ViewStateService, Service, ReplaceModel, AnalyticsService, CartModel) { - this.onMessageReceivedFromAdyen = function(event) { - console.log("event.source: ", event.source), console.log("event origin: ", event.origin), console.log("event data: ", event.data); - var deferred = $q.defer(); - switch (event.data) { - case "PAID": - console.log("TransactionService PAID"), deferred.resolve("PAID"), ReplaceModel.getState() === NOT_PURCHASED ? Service.getPurchases() : ViewStateService.viewRequested("downloads"), AnalyticsService.sendData(null, "transaction"), Service.getUserInfo(); - break; - case "CANCELED": - deferred.reject("CANCELED"), console.log("TransactionService CANCELED"); - break; - case "PENDING": - console.log("TransactionService PENDING"), deferred.reject("PENDING"); - break; - default: - deferred.reject("UNKNOWN") - } - return deferred.promise - } -}]), app.service("UnzipService", ["$rootScope", "DeleteOnFileSystemService", "ReplaceModel", "ImportAEService", function($rootScope, DeleteOnFileSystemService, ReplaceModel, ImportAEService) { - var call = { - unzippedCounter: 0, - deletedCounter: 0, - numOfItems: 0, - items: [], - deleteObjects: [], - itemObjects: [], - unzipItems: function(items) { - call.unzippedCounter = 0, call.deletedCounter = 0, call.numOfItems = items.length, call.items = items, call.deleteObjects = [], call.itemObjects = [], call.items.forEach(function(item) { - var itemObj = { - dest: item.downloadDestination + "AE " + item.id, - source: item.downloadDestination + item.fileName - }; - call.itemObjects.push(itemObj), call.deleteObjects.push(itemObj.source, itemObj.dest + path.sep + "__MACOSX"), call.unzip(itemObj) - }), console.log("UnzipService unzipItems numOfItems:", call.numOfItems), console.log("UnzipService unzipItems call.deleteObjects:", call.deleteObjects), console.log("UnzipService unzipItems call.deleteObjects.length:", call.deleteObjects.length) - }, - unzip: function(itemObj) { - var unzipper = new DecompressZip(itemObj.source); - unzipper.on("error", function(err) { - console.log("UnzipService Caught an error: ", err) - }), unzipper.on("extract", function(log) { - console.log("UnzipService Finished extracting"), call.unzippedCounter++, call.unzippedCounter === call.numOfItems && (console.log("UnzipService Finished extracting all items, unzippedCounter", call.unzippedCounter), DeleteOnFileSystemService.deleteFolder(call.deleteObjects, function() { - console.log("UnzipService zip or mac os folder deleted"), call.deletedCounter++, console.log("UnzipService call.deletedCounter: ", call.deletedCounter), console.log("UnzipService call.deleteObjects.length: ", call.deleteObjects.length), call.deletedCounter === call.deleteObjects.length && (console.log("UnzipService ALL zip or mac os folders deleted", ReplaceModel.getState()), call.itemObjects.forEach(function(item) { - ReplaceModel.getState() === NOT_DOWNLOADED && "AEFT" == HOST_NAME && ImportAEService.import(item.dest) - }), ReplaceModel.getState() === DEFAULT && 1 < call.numOfItems ? opn(call.items[0].downloadDestination) : ReplaceModel.getState() === DEFAULT && 1 === call.numOfItems && (console.log("UnzipService opn finder"), opn(itemObj.dest)), ReplaceModel.setState(DEFAULT)) - })) - }), unzipper.on("progress", function(fileIndex, fileCount) { - console.log("UnzipService Extracted file " + (fileIndex + 1) + " of " + fileCount) - }), unzipper.extract({ - path: itemObj.dest - }) - } - }; - return call -}]), app.factory("UserService", ["$rootScope", "AppModel", "LoginModel", function($rootScope, AppModel, LoginModel) { - var file, parsedLocalXML, cm, cx, result = { - readXML: function() { - file = AppModel.getUserXML(), fs.readFile(file, "utf8", function(err, data) { - if (err) throw err; - result.parseLocalXML(data) - }) - }, - saveData: function(cx, cm) { - parsedLocalXML.root.user[0].$.cm = cm, parsedLocalXML.root.user[0].$.cx = cx, result.writeToDisk() - }, - parseLocalXML: function(xml) { - var parser = new xml2js.Parser; - parser.addListener("end", function(res) { - if (cm = (parsedLocalXML = res).root.user[0].$.cm, cx = res.root.user[0].$.cx, 0 < cm.length && 0 < cx.length) { - LoginModel.setCX(cx), LoginModel.setCM(cm); - $rootScope.$emit("api call", { - fn: "getUserInfo" - }) - } - }), parser.parseString(xml) - }, - writeToDisk: function() { - var xml = (new xml2js.Builder).buildObject(parsedLocalXML); - fs.writeFile(file, xml, function(err) { - if (err) throw err - }) - } - }; - return result -}]), app.factory("ViewStateService", ["$rootScope", "ViewStateModel", "ReplaceModel", "LoginModel", function($rootScope, ViewStateModel, ReplaceModel, LoginModel) { - var requestedState, result = { - viewRequested: function(state) { - console.log("ViewStateService viewRequested: ", state), "downloads" !== (requestedState = state) && "previews" !== requestedState && "cart" !== requestedState || LoginModel.getLoggedIn() ? (ViewStateModel.setState(state), result.onViewApproved(!0)) : $rootScope.$emit("modal not logged in", [ERROR]) - }, - onViewApproved: function(result) { - if (console.log("ViewStateService onViewApproved ", result, requestedState), result) { - var fName; - switch (ViewStateModel.setState(requestedState), requestedState) { - case "downloads": - fName = "getPurchases"; - break; - case "previews": - fName = "getImportedPreviews"; - break; - case "cart": - fName = "getCart"; - break; - case "freebies": - fName = "getFreeClips"; - break; - case "bins": - fName = "getBin"; - break; - case "search": - default: - fName = "search" - } - $rootScope.$emit("api call", { - fn: fName - }) - } else console.log("ViewStateService onViewApproved cancel clicked in modal, stay in current view") - } - }; - return result -}]); -var imgHeight, imgWidth, COUNTRIES = [{ - name: "United States", - code: "US" - }, { - name: "Afghanistan", - code: "AF" - }, { - name: "Aland Islands", - code: "AX" - }, { - name: "Albania", - code: "AL" - }, { - name: "Algeria", - code: "DZ" - }, { - name: "American Samoa", - code: "AS" - }, { - name: "Andorra", - code: "AD" - }, { - name: "Angola", - code: "AO" - }, { - name: "Anguilla", - code: "AI" - }, { - name: "Antarctica", - code: "AQ" - }, { - name: "Antigua and Barbuda", - code: "AG" - }, { - name: "Argentina", - code: "AR" - }, { - name: "Armenia", - code: "AM" - }, { - name: "Aruba", - code: "AW" - }, { - name: "Australia", - code: "AU" - }, { - name: "Austria", - code: "AT" - }, { - name: "Azerbaijan", - code: "AZ" - }, { - name: "Bahamas", - code: "BS" - }, { - name: "Bahrain", - code: "BH" - }, { - name: "Bangladesh", - code: "BD" - }, { - name: "Barbados", - code: "BB" - }, { - name: "Belarus", - code: "BY" - }, { - name: "Belgium", - code: "BE" - }, { - name: "Belize", - code: "BZ" - }, { - name: "Benin", - code: "BJ" - }, { - name: "Bermuda", - code: "BM" - }, { - name: "Bhutan", - code: "BT" - }, { - name: "Bolivia", - code: "BO" - }, { - name: "Bosnia and Herzegovina", - code: "BA" - }, { - name: "Botswana", - code: "BW" - }, { - name: "Bouvet Island", - code: "BV" - }, { - name: "Brazil", - code: "BR" - }, { - name: "British Indian Ocean Territory", - code: "IO" - }, { - name: "Brunei Darussalam", - code: "BN" - }, { - name: "Bulgaria", - code: "BG" - }, { - name: "Burkina Faso", - code: "BF" - }, { - name: "Burundi", - code: "BI" - }, { - name: "Cambodia", - code: "KH" - }, { - name: "Cameroon", - code: "CM" - }, { - name: "Canada", - code: "CA" - }, { - name: "Cape Verde", - code: "CV" - }, { - name: "Cayman Islands", - code: "KY" - }, { - name: "Central African Republic", - code: "CF" - }, { - name: "Chad", - code: "TD" - }, { - name: "Chile", - code: "CL" - }, { - name: "China", - code: "CN" - }, { - name: "Christmas Island", - code: "CX" - }, { - name: "Cocos (Keeling) Islands", - code: "CC" - }, { - name: "Colombia", - code: "CO" - }, { - name: "Comoros", - code: "KM" - }, { - name: "Congo", - code: "CG" - }, { - name: "Congo, The Democratic Republic of the", - code: "CD" - }, { - name: "Cook Islands", - code: "CK" - }, { - name: "Costa Rica", - code: "CR" - }, { - name: "Cote D'Ivoire", - code: "CI" - }, { - name: "Croatia", - code: "HR" - }, { - name: "Cuba", - code: "CU" - }, { - name: "Cyprus", - code: "CY" - }, { - name: "Czech Republic", - code: "CZ" - }, { - name: "Denmark", - code: "DK" - }, { - name: "Djibouti", - code: "DJ" - }, { - name: "Dominica", - code: "DM" - }, { - name: "Dominican Republic", - code: "DO" - }, { - name: "Ecuador", - code: "EC" - }, { - name: "Egypt", - code: "EG" - }, { - name: "El Salvador", - code: "SV" - }, { - name: "Equatorial Guinea", - code: "GQ" - }, { - name: "Eritrea", - code: "ER" - }, { - name: "Estonia", - code: "EE" - }, { - name: "Ethiopia", - code: "ET" - }, { - name: "Falkland Islands (Malvinas)", - code: "FK" - }, { - name: "Faroe Islands", - code: "FO" - }, { - name: "Fiji", - code: "FJ" - }, { - name: "Finland", - code: "FI" - }, { - name: "France", - code: "FR" - }, { - name: "French Guiana", - code: "GF" - }, { - name: "French Polynesia", - code: "PF" - }, { - name: "French Southern Territories", - code: "TF" - }, { - name: "Gabon", - code: "GA" - }, { - name: "Gambia", - code: "GM" - }, { - name: "Georgia", - code: "GE" - }, { - name: "Germany", - code: "DE" - }, { - name: "Ghana", - code: "GH" - }, { - name: "Gibraltar", - code: "GI" - }, { - name: "Greece", - code: "GR" - }, { - name: "Greenland", - code: "GL" - }, { - name: "Grenada", - code: "GD" - }, { - name: "Guadeloupe", - code: "GP" - }, { - name: "Guam", - code: "GU" - }, { - name: "Guatemala", - code: "GT" - }, { - name: "Guernsey", - code: "GG" - }, { - name: "Guinea", - code: "GN" - }, { - name: "Guinea-Bissau", - code: "GW" - }, { - name: "Guyana", - code: "GY" - }, { - name: "Haiti", - code: "HT" - }, { - name: "Heard Island and Mcdonald Islands", - code: "HM" - }, { - name: "Holy See (Vatican City State)", - code: "VA" - }, { - name: "Honduras", - code: "HN" - }, { - name: "Hong Kong", - code: "HK" - }, { - name: "Hungary", - code: "HU" - }, { - name: "Iceland", - code: "IS" - }, { - name: "India", - code: "IN" - }, { - name: "Indonesia", - code: "ID" - }, { - name: "Iran, Islamic Republic Of", - code: "IR" - }, { - name: "Iraq", - code: "IQ" - }, { - name: "Ireland", - code: "IE" - }, { - name: "Isle of Man", - code: "IM" - }, { - name: "Israel", - code: "IL" - }, { - name: "Italy", - code: "IT" - }, { - name: "Jamaica", - code: "JM" - }, { - name: "Japan", - code: "JP" - }, { - name: "Jersey", - code: "JE" - }, { - name: "Jordan", - code: "JO" - }, { - name: "Kazakhstan", - code: "KZ" - }, { - name: "Kenya", - code: "KE" - }, { - name: "Kiribati", - code: "KI" - }, { - name: "Korea, Democratic People's Republic of", - code: "KP" - }, { - name: "Korea, Republic of", - code: "KR" - }, { - name: "Kuwait", - code: "KW" - }, { - name: "Kyrgyzstan", - code: "KG" - }, { - name: "Lao People's Democratic Republic", - code: "LA" - }, { - name: "Latvia", - code: "LV" - }, { - name: "Lebanon", - code: "LB" - }, { - name: "Lesotho", - code: "LS" - }, { - name: "Liberia", - code: "LR" - }, { - name: "Libyan Arab Jamahiriya", - code: "LY" - }, { - name: "Liechtenstein", - code: "LI" - }, { - name: "Lithuania", - code: "LT" - }, { - name: "Luxembourg", - code: "LU" - }, { - name: "Macao", - code: "MO" - }, { - name: "Macedonia, The Former Yugoslav Republic of", - code: "MK" - }, { - name: "Madagascar", - code: "MG" - }, { - name: "Malawi", - code: "MW" - }, { - name: "Malaysia", - code: "MY" - }, { - name: "Maldives", - code: "MV" - }, { - name: "Mali", - code: "ML" - }, { - name: "Malta", - code: "MT" - }, { - name: "Marshall Islands", - code: "MH" - }, { - name: "Martinique", - code: "MQ" - }, { - name: "Mauritania", - code: "MR" - }, { - name: "Mauritius", - code: "MU" - }, { - name: "Mayotte", - code: "YT" - }, { - name: "Mexico", - code: "MX" - }, { - name: "Micronesia, Federated States of", - code: "FM" - }, { - name: "Moldova, Republic of", - code: "MD" - }, { - name: "Monaco", - code: "MC" - }, { - name: "Mongolia", - code: "MN" - }, { - name: "Montserrat", - code: "MS" - }, { - name: "Morocco", - code: "MA" - }, { - name: "Mozambique", - code: "MZ" - }, { - name: "Myanmar", - code: "MM" - }, { - name: "Namibia", - code: "NA" - }, { - name: "Nauru", - code: "NR" - }, { - name: "Nepal", - code: "NP" - }, { - name: "Netherlands", - code: "NL" - }, { - name: "Netherlands Antilles", - code: "AN" - }, { - name: "New Caledonia", - code: "NC" - }, { - name: "New Zealand", - code: "NZ" - }, { - name: "Nicaragua", - code: "NI" - }, { - name: "Niger", - code: "NE" - }, { - name: "Nigeria", - code: "NG" - }, { - name: "Niue", - code: "NU" - }, { - name: "Norfolk Island", - code: "NF" - }, { - name: "Northern Mariana Islands", - code: "MP" - }, { - name: "Norway", - code: "NO" - }, { - name: "Oman", - code: "OM" - }, { - name: "Pakistan", - code: "PK" - }, { - name: "Palau", - code: "PW" - }, { - name: "Palestinian Territory, Occupied", - code: "PS" - }, { - name: "Panama", - code: "PA" - }, { - name: "Papua New Guinea", - code: "PG" - }, { - name: "Paraguay", - code: "PY" - }, { - name: "Peru", - code: "PE" - }, { - name: "Philippines", - code: "PH" - }, { - name: "Pitcairn", - code: "PN" - }, { - name: "Poland", - code: "PL" - }, { - name: "Portugal", - code: "PT" - }, { - name: "Puerto Rico", - code: "PR" - }, { - name: "Qatar", - code: "QA" - }, { - name: "Reunion", - code: "RE" - }, { - name: "Romania", - code: "RO" - }, { - name: "Russian Federation", - code: "RU" - }, { - name: "Rwanda", - code: "RW" - }, { - name: "Saint Helena", - code: "SH" - }, { - name: "Saint Kitts and Nevis", - code: "KN" - }, { - name: "Saint Lucia", - code: "LC" - }, { - name: "Saint Pierre and Miquelon", - code: "PM" - }, { - name: "Saint Vincent and the Grenadines", - code: "VC" - }, { - name: "Samoa", - code: "WS" - }, { - name: "San Marino", - code: "SM" - }, { - name: "Sao Tome and Principe", - code: "ST" - }, { - name: "Saudi Arabia", - code: "SA" - }, { - name: "Senegal", - code: "SN" - }, { - name: "Serbia and Montenegro", - code: "CS" - }, { - name: "Seychelles", - code: "SC" - }, { - name: "Sierra Leone", - code: "SL" - }, { - name: "Singapore", - code: "SG" - }, { - name: "Slovakia", - code: "SK" - }, { - name: "Slovenia", - code: "SI" - }, { - name: "Solomon Islands", - code: "SB" - }, { - name: "Somalia", - code: "SO" - }, { - name: "South Africa", - code: "ZA" - }, { - name: "South Georgia and the South Sandwich Islands", - code: "GS" - }, { - name: "Spain", - code: "ES" - }, { - name: "Sri Lanka", - code: "LK" - }, { - name: "Sudan", - code: "SD" - }, { - name: "Suriname", - code: "SR" - }, { - name: "Svalbard and Jan Mayen", - code: "SJ" - }, { - name: "Swaziland", - code: "SZ" - }, { - name: "Sweden", - code: "SE" - }, { - name: "Switzerland", - code: "CH" - }, { - name: "Syrian Arab Republic", - code: "SY" - }, { - name: "Taiwan, Province of China", - code: "TW" - }, { - name: "Tajikistan", - code: "TJ" - }, { - name: "Tanzania, United Republic of", - code: "TZ" - }, { - name: "Thailand", - code: "TH" - }, { - name: "Timor-Leste", - code: "TL" - }, { - name: "Togo", - code: "TG" - }, { - name: "Tokelau", - code: "TK" - }, { - name: "Tonga", - code: "TO" - }, { - name: "Trinidad and Tobago", - code: "TT" - }, { - name: "Tunisia", - code: "TN" - }, { - name: "Turkey", - code: "TR" - }, { - name: "Turkmenistan", - code: "TM" - }, { - name: "Turks and Caicos Islands", - code: "TC" - }, { - name: "Tuvalu", - code: "TV" - }, { - name: "Uganda", - code: "UG" - }, { - name: "Ukraine", - code: "UA" - }, { - name: "United Arab Emirates", - code: "AE" - }, { - name: "United Kingdom", - code: "GB" - }, { - name: "United States", - code: "US" - }, { - name: "United States Minor Outlying Islands", - code: "UM" - }, { - name: "Uruguay", - code: "UY" - }, { - name: "Uzbekistan", - code: "UZ" - }, { - name: "Vanuatu", - code: "VU" - }, { - name: "Venezuela", - code: "VE" - }, { - name: "Vietnam", - code: "VN" - }, { - name: "Virgin Islands, British", - code: "VG" - }, { - name: "Virgin Islands, U.S.", - code: "VI" - }, { - name: "Wallis and Futuna", - code: "WF" - }, { - name: "Western Sahara", - code: "EH" - }, { - name: "Yemen", - code: "YE" - }, { - name: "Zambia", - code: "ZM" - }, { - name: "Zimbabwe", - code: "ZW" - }], - STATES = [{ - name: "Alabama", - label: "Alabama", - code: "AL" - }, { - name: "Alaska", - label: "Alaska", - code: "AK" - }, { - name: "American Samoa", - label: "American Samoa", - code: "AS" - }, { - name: "Arizona", - label: "Arizona", - code: "AZ" - }, { - name: "Arkansas", - label: "Arkansas", - code: "AR" - }, { - name: "Armed Forces Europe", - label: "Armed Forces Europe", - code: "AE" - }, { - name: "Armed Forces Pacific", - label: "Armed Forces Pacific", - code: "AP" - }, { - name: "Armed Forces the Americas", - label: "Armed Forces the Americas", - code: "AA" - }, { - name: "California", - label: "California", - code: "CA" - }, { - name: "Colorado", - label: "Colorado", - code: "CO" - }, { - name: "Connecticut", - label: "Connecticut", - code: "CT" - }, { - name: "Delaware", - label: "Delaware", - code: "DE" - }, { - name: "District of Columbia", - label: "District of Columbia", - code: "DC" - }, { - name: "Federated States of Micronesia", - label: "Federated States of Micronesia", - code: "FM" - }, { - name: "Florida", - label: "Florida", - code: "FL" - }, { - name: "Georgia", - label: "Georgia", - code: "GA" - }, { - name: "Guam", - label: "Guam", - code: "GU" - }, { - name: "Hawaii", - label: "Hawaii", - code: "HI" - }, { - name: "Idaho", - label: "Idaho", - code: "ID" - }, { - name: "Illinois", - label: "Illinois", - code: "IL" - }, { - name: "Indiana", - label: "Indiana", - code: "IN" - }, { - name: "Iowa", - label: "Iowa", - code: "IA" - }, { - name: "Kansas", - label: "Kansas", - code: "KS" - }, { - name: "Kentucky", - label: "Kentucky", - code: "KY" - }, { - name: "Louisiana", - label: "Louisiana", - code: "LA" - }, { - name: "Maine", - label: "Maine", - code: "ME" - }, { - name: "Marshall Islands", - label: "Marshall Islands", - code: "MH" - }, { - name: "Maryland", - label: "Maryland", - code: "MD" - }, { - name: "Massachusetts", - label: "Massachusetts", - code: "MA" - }, { - name: "Michigan", - label: "Michigan", - code: "MI" - }, { - name: "Minnesota", - label: "Minnesota", - code: "MN" - }, { - name: "Mississippi", - label: "Mississippi", - code: "MS" - }, { - name: "Missouri", - label: "Missouri", - code: "MO" - }, { - name: "Montana", - label: "Montana", - code: "MT" - }, { - name: "Nebraska", - label: "Nebraska", - code: "NE" - }, { - name: "Nevada", - label: "Nevada", - code: "NV" - }, { - name: "New Hampshire", - label: "New Hampshire", - code: "NH" - }, { - name: "New Jersey", - label: "New Jersey", - code: "NJ" - }, { - name: "New Mexico", - label: "New Mexico", - code: "NM" - }, { - name: "New York", - label: "New York", - code: "NY" - }, { - name: "North Carolina", - label: "North Carolina", - code: "NC" - }, { - name: "North Dakota", - label: "North Dakota", - code: "ND" - }, { - name: "Northern Mariana Islands", - label: "Northern Mariana Islands", - code: "MP" - }, { - name: "Ohio", - label: "Ohio", - code: "OH" - }, { - name: "Oklahoma", - label: "Oklahoma", - code: "OK" - }, { - name: "Oregon", - label: "Oregon", - code: "OR" - }, { - name: "Pennsylvania", - label: "Pennsylvania", - code: "PA" - }, { - name: "Puerto Rico", - label: "Puerto Rico", - code: "PR" - }, { - name: "Rhode Island", - label: "Rhode Island", - code: "RI" - }, { - name: "South Carolina", - label: "South Carolina", - code: "SC" - }, { - name: "South Dakota", - label: "South Dakota", - code: "SD" - }, { - name: "Tennessee", - label: "Tennessee", - code: "TN" - }, { - name: "Texas", - label: "Texas", - code: "TX" - }, { - name: "Utah", - label: "Utah", - code: "UT" - }, { - name: "Vermont", - label: "Vermont", - code: "VT" - }, { - name: "Virgin Islands, U.S.", - label: "Virgin Islands, U.S.", - code: "VI" - }, { - name: "Virginia", - label: "Virginia", - code: "VA" - }, { - name: "Washington", - label: "Washington", - code: "WA" - }, { - name: "West Virginia", - label: "West Virginia", - code: "WV" - }, { - name: "Wisconsin", - label: "Wisconsin", - code: "WI" - }, { - name: "Wyoming", - label: "Wyoming", - code: "WY" - }]; - -function get_browser() { - var tem, ua = navigator.userAgent, - M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || []; - return /trident/i.test(M[1]) ? "IE " + ((tem = /\brv[ :]+(\d+)/g.exec(ua) || [])[1] || "") : "Chrome" === M[1] && null != (tem = ua.match(/\bOPR\/(\d+)/)) ? "Opera " + tem[1] : (M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, "-?"], null != (tem = ua.match(/version\/(\d+)/i)) && M.splice(1, 1, tem[1]), M[0]) -} - -function get_browser_version() { - var tem, ua = navigator.userAgent, - M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || []; - return /trident/i.test(M[1]) ? "IE " + ((tem = /\brv[ :]+(\d+)/g.exec(ua) || [])[1] || "") : "Chrome" === M[1] && null != (tem = ua.match(/\bOPR\/(\d+)/)) ? "Opera " + tem[1] : (M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, "-?"], null != (tem = ua.match(/version\/(\d+)/i)) && M.splice(1, 1, tem[1]), M[1]) -} - -function findHHandWW() { - return imgHeight = this.height, imgWidth = this.width, !0 -} - -function showImage(imgPath) { - var myImage = new Image; - myImage.name = imgPath, myImage.onload = findHHandWW, myImage.src = imgPath -} - -function log(className, prefix, obj) { - if (prefix = " " + prefix + ": ", obj instanceof Array) obj.forEach(function(entry) { - log(className, "item", entry) - }); - else - for (key in console.log(className + ":"), obj) console.log(prefix + key + ": " + obj[key]), "formats" === key && obj[key].forEach(function(entry) { - log(className, " format", entry) - }), "versions" === key && obj[key].forEach(function(entry) { - log(className, " versions", entry) - }) -} - -function ExtendedID() {} - -function getAbbrName(name, len) { - return name && name.length > len ? name.slice(0, len) + "..." : name -} - -function convertArrayToCommaSeperatedString(ids) { - var idsToString = ""; - return ids.forEach(function(id) { - idsToString += id + "," - }), idsToString = idsToString.slice(0, -1) -} - -function getFormattedName(input) { - for (; - 1 != input.indexOf(",");) input = input.replace(",", " "); - for (; - 1 != input.indexOf("&");) input = input.replace("&", "and"); - for (; - 1 != input.indexOf("/");) input = input.replace("/", " "); - for (; - 1 != input.indexOf("'");) input = input.replace("'", " "); - for (; - 1 != input.indexOf("(");) input = input.replace("(", " "); - for (; - 1 != input.indexOf(")");) input = input.replace(")", " "); - for (; - 1 != input.indexOf(":");) input = input.replace(":", " "); - for (; - 1 != input.indexOf(" ");) input = input.replace(" ", " "); - return input -} - -function getUID() { - var d = (new Date).getTime(); - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) { - var r = (d + 16 * Math.random()) % 16 | 0; - return d = Math.floor(d / 16), ("x" == c ? r : 3 & r | 8).toString(16) - }) -} - -function getStringPosition(string, subString, index) { - return string.split(subString, index).join(subString).length -} - -function gup(name, url) { - url || (url = location.href), name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); - var results = new RegExp("[\\?&]" + name + "=([^&#]*)").exec(url); - return null == results ? null : results[1] -} - -function checkVersion(tv, uv) { - var updaterVersion = uv; - if (tv === updaterVersion) return !1; - var splitThis = tv.split("."), - splitThisInt = []; - splitThis.forEach(function(string) { - splitThisInt.push(parseInt(string)) - }); - var splitUpdater = updaterVersion.split("."), - splitUpdaterInt = []; - return splitUpdater.forEach(function(string) { - splitUpdaterInt.push(parseInt(string)) - }), splitUpdaterInt[0] > splitThisInt[0] || (splitUpdaterInt[0] >= splitThisInt[0] && splitUpdaterInt[1] > splitThisInt[1] || splitUpdaterInt[0] >= splitThisInt[0] && splitUpdaterInt[1] >= splitThisInt[1] && splitUpdaterInt[2] > splitThisInt[2]) -} - -function getConvertedVideoStandard(vs) { - var standard; - switch (parseInt(vs)) { - case 0: - standard = "Multimedia / Unknown"; - break; - case 1: - standard = "NTSC D1"; - break; - case 2: - standard = "NTSC DV"; - break; - case 3: - standard = "PAL / PAL DV"; - break; - case 4: - standard = "HD 1080"; - break; - case 5: - standard = "HDV 720p"; - break; - case 6: - standard = "Other Hi-Def"; - break; - case 7: - standard = "Multimedia"; - break; - case 8: - standard = "HDV 1080i"; - break; - case 9: - standard = "HD 720"; - break; - case 10: - standard = "4k+"; - break; - case 100: - standard = "Music"; - break; - case 101: - standard = "Sound effect"; - break; - case 200: - standard = "AE"; - break; - case 300: - standard = "Photo"; - break; - case 301: - standard = "Illustration"; - break; - case 400: - standard = "3D" - } - return standard -} - -function getMediaType(vs) { - var type; - switch (vs) { - case "Music": - case "Sound effect": - case "Photo": - case "Illustration": - case "AE": - type = vs; - break; - default: - type = "Video" - } - return type -} -Number.prototype.formatMoney = function(decPlaces, thouSeparator, decSeparator, currencySymbol) { - decPlaces = isNaN(decPlaces = Math.abs(decPlaces)) ? 2 : decPlaces, decSeparator = null == decSeparator ? "." : decSeparator, thouSeparator = null == thouSeparator ? "," : thouSeparator, currencySymbol = null == currencySymbol ? "$" : currencySymbol; - var n = this, - sign = n < 0 ? "-" : "", - i = parseInt(n = Math.abs(+n || 0).toFixed(decPlaces)) + "", - j = 3 < (j = i.length) ? j % 3 : 0; - return sign + currencySymbol + (j ? i.substr(0, j) + thouSeparator : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thouSeparator) + (decPlaces ? decSeparator + Math.abs(n - i).toFixed(decPlaces).slice(2) : "") - }, - function() { - function Point(x, y) { - this.x = x || 0, this.y = y || 0 - } - Point.prototype.x = null, Point.prototype.y = null, Point.prototype.add = function(v) { - return new Point(this.x + v.x, this.y + v.y) - }, Point.prototype.clone = function() { - return new Point(this.x, this.y) - }, Point.prototype.degreesTo = function(v) { - var dx = this.x - v.x, - dy = this.y - v.y; - return Math.atan2(dy, dx) * (180 / Math.PI) - }, Point.prototype.distance = function(v) { - var x = this.x - v.x, - y = this.y - v.y; - return Math.sqrt(x * x + y * y) - }, Point.prototype.equals = function(toCompare) { - return this.x == toCompare.x && this.y == toCompare.y - }, Point.prototype.interpolate = function(v, f) { - return new Point((this.x + v.x) * f, (this.y + v.y) * f) - }, Point.prototype.length = function() { - return Math.sqrt(this.x * this.x + this.y * this.y) - }, Point.prototype.normalize = function(thickness) { - var l = this.length(); - this.x = this.x / l * thickness, this.y = this.y / l * thickness - }, Point.prototype.orbit = function(origin, arcWidth, arcHeight, degrees) { - var radians = degrees * (Math.PI / 180); - this.x = origin.x + arcWidth * Math.cos(radians), this.y = origin.y + arcHeight * Math.sin(radians) - }, Point.prototype.offset = function(dx, dy) { - this.x += dx, this.y += dy - }, Point.prototype.subtract = function(v) { - return new Point(this.x - v.x, this.y - v.y) - }, Point.prototype.toString = function() { - return "(x=" + this.x + ", y=" + this.y + ")" - }, Point.interpolate = function(pt1, pt2, f) { - return new Point((pt1.x + pt2.x) * f, (pt1.y + pt2.y) * f) - }, Point.polar = function(len, angle) { - return new Point(len * Math.sin(angle), len * Math.cos(angle)) - }, Point.distance = function(pt1, pt2) { - var x = pt1.x - pt2.x, - y = pt1.y - pt2.y; - return Math.sqrt(x * x + y * y) - }, this.Point = window.Point = Point - }(), ExtendedID.extend = function(id) { - if (id) { - for (var extendedID = id.toString(); extendedID.length < 9;) extendedID = "0" + extendedID; - return extendedID - } - }, String.prototype.insert = function(index, string) { - return 0 < index ? this.substring(0, index) + string + this.substring(index, this.length) : string + this - }, String.prototype.replaceAll = function(search, replacement) { - return this.replace(new RegExp(search, "g"), replacement) - }, getMousePosition = function(element) { - for (var xPosition = 0, yPosition = 0; element;) xPosition += element.offsetLeft - element.scrollLeft + element.clientLeft, yPosition += element.offsetTop - element.scrollTop + element.clientTop, element = element.offsetParent; - return { - x: xPosition, - y: yPosition - } - }, getScroll = function() { - if (null != window.pageYOffset) return [pageXOffset, pageYOffset]; - var d = document, - r = d.documentElement, - b = d.body; - return [r.scrollLeft || b.scrollLeft || 0, r.scrollTop || b.scrollTop || 0] - }, getUserHome = function() { - return require("os").homedir() - }, getName = function(input) { - for (; - 1 != input.indexOf(",");) input = input.replace(",", " "); - for (; - 1 != input.indexOf("&");) input = input.replace("&", "and"); - for (; - 1 != input.indexOf("/");) input = input.replace("/", " "); - for (; - 1 != input.indexOf("'");) input = input.replace("'", " "); - for (; - 1 != input.indexOf("(");) input = input.replace("(", " "); - for (; - 1 != input.indexOf(")");) input = input.replace(")", " "); - for (; - 1 != input.indexOf(":");) input = input.replace(":", " "); - return input - }, getPosition = function(element) { - for (var xPosition = 0, yPosition = 0; element;) xPosition += element.offsetLeft - element.scrollLeft + element.clientLeft, yPosition += element.offsetTop - element.scrollTop + element.clientTop, element = element.offsetParent; - return { - x: xPosition, - y: yPosition - } - }, getChromeVersion = function() { - var raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./); - return !!raw && parseInt(raw[2], 10) - }; diff --git a/pype/aport/static/index.html b/pype/aport/static/index.html deleted file mode 100644 index d9ed3b82180..00000000000 --- a/pype/aport/static/index.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - Pype extention - - - - - - - - - - - - - - - - Refresh panel -
-
-
-
    -
  1. -

    Set context here

    -
    - ProjectAssettaskapp - -
  2. -
  3. -

    deregister_plugin_path

    -
    - -
  4. -
  5. -

    register_plugin_path

    -
    - Path: - -
  6. -
  7. -

    Publish

    -
    - Json path: - Gui - -
  8. - -
-
-
-
-
- -
-
-
-
-
- - - - - diff --git a/pype/aport/static/script.js b/pype/aport/static/script.js deleted file mode 100644 index 417f5052d35..00000000000 --- a/pype/aport/static/script.js +++ /dev/null @@ -1,214 +0,0 @@ -var api = pico.importModule('api'); - -var output = document.getElementById('output'); - -function querySelector(parent){ - return function(child){ - return document.querySelector(parent).querySelector(child) - }; -} - -var defs = {} -function jumpTo(name){ - var e = defs[name]; - document.querySelectorAll('.highlight').forEach(function(el){ - el.classList.remove('highlight'); - }); - e.classList.add('highlight'); - return false; -} - -function displayResult(r){ - output.classList.remove("error"); - output.innerText = JSON.stringify(r); -} - -function displayError(e){ - output.classList.add("error"); - output.innerText = e.message; -} - -function unindent(code){ - var lines = code.split('\n'); - var margin = -1; - for(var j=0; j < lines.length; j++){ - var l = lines[j]; - for(i=0; i < l.length; i++){ - if(l[i] != " "){ - margin = i; - break; - } - } - if(margin > -1){ - break; - } - } - lines = lines.slice(j); - return lines.map(function(s){ return s.substr(margin)}).join('\n'); -} - -function deregister(){ - var $ = querySelector("#deregister"); - api.deregister_plugin_path().then(displayResult); -} - -function register(){ - var $ = querySelector("#register"); - var path = $("input[name=path]").value; - api.register_plugin_path(path).then(displayResult); -} - - -function publish(){ - var $ = querySelector("#publish"); - var path = $("input[name=path]").value; - var gui = $("input[name=gui]").checked; - api.publish(path, gui).then(displayResult); -} - -function context(){ - var $ = querySelector("#context"); - var project = $("input[name=project]").value; - var asset = $("input[name=asset]").value; - var task = $("input[name=task]").value; - var app = $("input[name=app]").value; - api.context(project,asset,task,app).then(displayResult); -} - - -// -// function example1(){ -// var $ = querySelector("#example1"); -// var name = $("input[name=name]").value; -// api.hello(name).then(displayResult); -// } -// -// -// function example2(){ -// var $ = querySelector("#example2"); -// var x = $("input[name=x]").valueAsNumber; -// var y = $("#example2 input[name=y]").valueAsNumber; -// api.multiply(x, y).then(displayResult); -// } -// -// function example3(){ -// var $ = querySelector("#example3"); -// var file = $("input[name=upload]").files[0]; -// api.upload(file, file.name).then(displayResult).catch(displayError); -// } -// -// function example4(){ -// var $ = querySelector("#example4"); -// api.my_ip().then(displayResult) -// } -// -// function example5(){ -// var $ = querySelector("#example5"); -// var username = $("input[name=username]").value; -// var password = $("input[name=password]").value; -// pico.setAuthentication(api, username, password); -// api.current_user().then(displayResult).catch(displayError); -// pico.clearAuthentication(api); -// } -// -// function example6(){ -// var $ = querySelector("#example6"); -// api.start_session().then(function(){ -// api.session_id().then(displayResult).then(function(){ -// api.end_session(); -// }) -// }) -// } -// -// function example7(){ -// var $ = querySelector("#example7"); -// var session_id = "4242"; -// pico.setRequestHook(api, 'session', function(req) { -// req.headers.set('X-SESSION-ID', session_id) -// }) -// api.session_id2().then(displayResult) -// pico.clearRequestHook(api, 'session'); -// } -// -// function example8(){ -// var $ = querySelector("#example8"); -// api.countdown(10).each(displayResult).then(function(){ -// displayResult("Boom!"); -// }); -// } -// -// function example9(){ -// var $ = querySelector("#example9"); -// var user = { -// name: "Bob", -// age: 30, -// occupation: "Software Engineer", -// } -// api.user_description(user).then(displayResult); -// } -// -// function example10(){ -// var $ = querySelector("#example10"); -// api.fail().then(displayResult).catch(displayError); -// } -// -// function example11(){ -// var $ = querySelector("#example11"); -// api.make_coffee().then(displayResult).catch(displayError); -// } -// -// -// function example12(){ -// var $ = querySelector("#example12"); -// var form = $("form"); -// api.multiply.submitFormData(new FormData(form)).then(displayResult).catch(displayError); -// } -// -// function example13(){ -// var $ = querySelector("#example13"); -// var data = { -// x: 6, -// y: 7, -// } -// api.multiply.submitJSON(data).then(displayResult).catch(displayError); -// } - - -// api.show_source().then(function(s){ -// document.querySelector('#source code').innerText = s; -// }).then(ready); - - -function ready(){ - // // set the element of each example to the corresponding functions source - // document.querySelectorAll('li pre code.js').forEach(function(e){ - // var id = e.parentElement.parentElement.id; - // var f = window[id]; - // var code = f.toString().split('\n').slice(2, -1).join('\n'); - // e.innerText = unindent(code); - // }) - - document.querySelectorAll('li pre code.html').forEach(function(e){ - var html = e.parentElement.parentElement.querySelector('div.example').innerHTML; - e.innerText = unindent(html); - }) - - hljs.initHighlighting(); - - // // find all the elements representing the function definitions in the python source - // document.querySelectorAll('.python .hljs-function .hljs-title').forEach(function(e){ - // var a = document.createElement('a'); - // a.name = e.innerText; - // e.parentElement.insertBefore(a, e) - // return defs[e.innerText] = e.parentElement; - // }); - - // convert all 'api.X' strings to hyperlinks to jump to python source - document.querySelectorAll('.js').forEach(function(e){ - var code = e.innerHTML; - Object.keys(defs).forEach(function(k){ - code = code.replace('api.' + k + '(', 'api.' + k + '('); - }) - e.innerHTML = code; - }) -} diff --git a/pype/aport/templates.py b/pype/aport/templates.py deleted file mode 100644 index 5be6e276ba4..00000000000 --- a/pype/aport/templates.py +++ /dev/null @@ -1,41 +0,0 @@ -from pype import api as pype - -log = pype.Logger.getLogger(__name__, "aport") - - -def get_anatomy(**kwarg): - return pype.Anatomy - - -def get_dataflow(**kwarg): - log.info(kwarg) - host = kwarg.get("host", "aport") - cls = kwarg.get("class", None) - preset = kwarg.get("preset", None) - assert any([host, cls]), log.error("aport.templates.get_dataflow():" - "Missing mandatory kwargs `host`, `cls`") - - aport_dataflow = getattr(pype.Dataflow, str(host), None) - aport_dataflow_node = getattr(aport_dataflow.nodes, str(cls), None) - if preset: - aport_dataflow_node = getattr(aport_dataflow_node, str(preset), None) - - log.info("Dataflow: {}".format(aport_dataflow_node)) - return aport_dataflow_node - - -def get_colorspace(**kwarg): - log.info(kwarg) - host = kwarg.get("host", "aport") - cls = kwarg.get("class", None) - preset = kwarg.get("preset", None) - assert any([host, cls]), log.error("aport.templates.get_colorspace():" - "Missing mandatory kwargs `host`, `cls`") - - aport_colorspace = getattr(pype.Colorspace, str(host), None) - aport_colorspace_node = getattr(aport_colorspace, str(cls), None) - if preset: - aport_colorspace_node = getattr(aport_colorspace_node, str(preset), None) - - log.info("Colorspace: {}".format(aport_colorspace_node)) - return aport_colorspace_node diff --git a/pype/avalon_apps/rest_api.py b/pype/avalon_apps/rest_api.py index ae027383a1d..1267ee39928 100644 --- a/pype/avalon_apps/rest_api.py +++ b/pype/avalon_apps/rest_api.py @@ -23,7 +23,9 @@ def get_project(self, request): if not project_name: output = {} for project_name in self.dbcon.tables(): - project = self.dbcon[project_name].find_one({"type": "project"}) + project = self.dbcon[project_name].find_one({ + "type": "project" + }) output[project_name] = project return CallbackResult(data=self.result_to_json(output)) @@ -44,7 +46,7 @@ def get_assets(self, request): if not self.dbcon.exist_table(_project_name): abort(404, "Project \"{}\" was not found in database".format( - project_name + _project_name )) if not _asset: @@ -65,9 +67,27 @@ def get_assets(self, request): return asset abort(404, "Asset \"{}\" with {} was not found in project {}".format( - _asset, identificator, project_name + _asset, identificator, _project_name )) + @RestApi.route("/publish/", + url_prefix="/premiere", methods="GET") + def publish(self, request): + """ + http://localhost:8021/premiere/publish/shot021?json_in=this/path/file_in.json&json_out=this/path/file_out.json + """ + asset_name = request.url_data["asset_name"] + query = request.query + data = request.request_data + + output = { + "message": "Got your data. Thanks.", + "your_data": data, + "your_query": query, + "your_asset_is": asset_name + } + return CallbackResult(data=self.result_to_json(output)) + def result_to_json(self, result): """ Converts result of MongoDB query to dict without $oid (ObjectId) keys with help of regex matching. diff --git a/pype/hooks/premiere/prelaunch.py b/pype/hooks/premiere/prelaunch.py new file mode 100644 index 00000000000..f2edb60195a --- /dev/null +++ b/pype/hooks/premiere/prelaunch.py @@ -0,0 +1,42 @@ +import os +import traceback +from pype.lib import PypeHook +from pypeapp import Logger +from pype.premiere import lib as prlib + + +class PremierePrelaunch(PypeHook): + """ + This hook will check if current workfile path has Adobe Premiere + project inside. IF not, it initialize it and finally it pass + path to the project by environment variable to Premiere launcher + shell script. + """ + + def __init__(self, logger=None): + if not logger: + self.log = Logger().get_logger(self.__class__.__name__) + else: + self.log = logger + + self.signature = "( {} )".format(self.__class__.__name__) + + def execute(self, *args, env: dict = None) -> bool: + + if not env: + env = os.environ + + try: + __import__("pype.premiere") + __import__("pyblish") + + except ImportError as e: + print(traceback.format_exc()) + print("pyblish: Could not load integration: %s " % e) + + else: + # Premiere Setup integration + # importlib.reload(prlib) + prlib.setup(env) + + return True diff --git a/pype/plugins/adobecommunicator/publish/collect_context.py b/pype/plugins/adobecommunicator/publish/collect_context.py new file mode 100644 index 00000000000..139dd86480e --- /dev/null +++ b/pype/plugins/adobecommunicator/publish/collect_context.py @@ -0,0 +1,92 @@ +import os +import pyblish.api +from avalon import ( + io, + api as avalon +) +import json +from pathlib import Path + + +class CollectContextDataFromAport(pyblish.api.ContextPlugin): + """ + Collecting temp json data sent from a host context + and path for returning json data back to hostself. + + Setting avalon session into correct context + + Args: + context (obj): pyblish context session + + """ + + label = "AdobeCommunicator Collect Context" + order = pyblish.api.CollectorOrder - 0.49 + + def process(self, context): + self.log.info( + "registred_hosts: `{}`".format(pyblish.api.registered_hosts())) + io.install() + # get json paths from data + input_json_path = os.environ.get("AC_PUBLISH_INPATH") + output_json_path = os.environ.get("AC_PUBLISH_OUTPATH") + + rqst_json_data_path = Path(input_json_path) + post_json_data_path = Path(output_json_path) + + context.data['post_json_data_path'] = str(post_json_data_path) + + # get avalon session data and convert \ to / + _S = avalon.session + + projects = Path(_S["AVALON_PROJECTS"]).resolve() + asset = _S["AVALON_ASSET"] + workdir = Path(_S["AVALON_WORKDIR"]).resolve() + _S["AVALON_PROJECTS"] = str(projects) + _S["AVALON_WORKDIR"] = str(workdir) + + context.data["avalonSession"] = _S + self.log.info(f"__ avalonSession: `{_S}`") + + # get stagin directory from recieved path to json + context.data["stagingDir"] = post_json_data_path.parent + + # get data from json file recieved + with rqst_json_data_path.open(mode='r') as f: + context.data["jsonData"] = json_data = json.load(f) + assert json_data, "No `data` in json file" + + # get and check host type + host = json_data.get("host", None) + host_version = json_data.get("hostVersion", None) + assert host, "No `host` data in json file" + assert host_version, "No `hostVersion` data in json file" + context.data["host"] = _S["AVALON_APP"] = host + context.data["hostVersion"] = \ + _S["AVALON_APP_VERSION"] = host_version + + # get current file + current_file = json_data.get("currentFile", None) + assert current_file, "No `currentFile` data in json file" + context.data["currentFile"] = str(Path(current_file).resolve()) + + # get project data from avalon + project_data = io.find_one({'type': 'project'}) + assert project_data, "No `project_data` data in avalon db" + context.data["projectData"] = project_data + self.log.debug("project_data: {}".format(project_data)) + + # get asset data from avalon and fix all paths + asset_data = io.find_one({ + "type": 'asset', + "name": asset + })["data"] + assert asset_data, "No `asset_data` data in avalon db" + + context.data["assetData"] = asset_data + + self.log.debug("asset_data: {}".format(asset_data)) + self.log.info("rqst_json_data_path is: {}".format(rqst_json_data_path)) + self.log.info("post_json_data_path is: {}".format(post_json_data_path)) + + # self.log.info("avalon.session is: {}".format(avalon.session)) diff --git a/pype/plugins/aport/publish/collect_instances.py b/pype/plugins/adobecommunicator/publish/collect_instances.py similarity index 60% rename from pype/plugins/aport/publish/collect_instances.py rename to pype/plugins/adobecommunicator/publish/collect_instances.py index 0af2215dca3..562dc08565c 100644 --- a/pype/plugins/aport/publish/collect_instances.py +++ b/pype/plugins/adobecommunicator/publish/collect_instances.py @@ -1,12 +1,5 @@ import os -import json import pyblish.api -from avalon import ( - io, - api as avalon -) - -from pype import api as pype class CollectInstancesFromJson(pyblish.api.ContextPlugin): @@ -26,7 +19,11 @@ class CollectInstancesFromJson(pyblish.api.ContextPlugin): def process(self, context): - a_session = context.data.get("avalonSession") + _S = context.data["avalonSession"] + asset = _S["AVALON_ASSET"] + task = _S["AVALON_TASK"] + host = _S["AVALON_APP"] + json_data = context.data.get("jsonData", None) assert json_data, "No `json_data` data in json file" @@ -36,96 +33,91 @@ def process(self, context): staging_dir = json_data.get("stagingDir", None) assert staging_dir, "No `stagingDir` path in json file" - presets = context.data["presets"] - rules_tasks = presets["rules_tasks"] - ftrack_types = rules_tasks["ftrackTypes"] - assert ftrack_types, "No `ftrack_types` data in `/templates/presets/[host]/rules_tasks.json` file" + host = context.data["host"] + presets = context.data["presets"][host] - context.data["ftrackTypes"] = ftrack_types + rules_tasks = presets["rules_tasks"] asset_default = presets["asset_default"] - assert asset_default, "No `asset_default` data in `/templates/presets/[host]/asset_default.json` file" - - asset_name = a_session["AVALON_ASSET"] - entity = io.find_one({"name": asset_name, - "type": "asset"}) + assert asset_default, ("No `asset_default` data in" + "`/presets/[host]/asset_default.json` file") # get frame start > first try from asset data - frame_start = context.data["assetData"].get("fstart", None) + frame_start = context.data["assetData"].get("frameStart", None) if not frame_start: - self.log.debug("frame_start not on assetData") - # get frame start > second try from parent data - frame_start = pype.get_data_hierarchical_attr(entity, "fstart") - if not frame_start: - self.log.debug("frame_start not on any parent entity") - # get frame start > third try from parent data - frame_start = asset_default["fstart"] + self.log.debug("frame_start not on any parent entity") + # get frame start > third try from parent data + frame_start = asset_default["frameStart"] assert frame_start, "No `frame_start` data found, " "please set `fstart` on asset" self.log.debug("frame_start: `{}`".format(frame_start)) # get handles > first try from asset data - handles = context.data["assetData"].get("handles", None) - if not handles: + handle_start = context.data["assetData"].get("handleStart", None) + handle_end = context.data["assetData"].get("handleEnd", None) + if (handle_start is None) or (handle_end is None): # get frame start > second try from parent data - handles = pype.get_data_hierarchical_attr(entity, "handles") - if not handles: - # get frame start > third try from parent data - handles = asset_default["handles"] + handle_start = asset_default.get("handleStart", None) + handle_end = asset_default.get("handleEnd", None) - assert handles, "No `handles` data found, " - "please set `fstart` on asset" - self.log.debug("handles: `{}`".format(handles)) + assert ( + (handle_start is not None) or ( + handle_end is not None)), ( + "No `handle_start, handle_end` data found") instances = [] - task = a_session["AVALON_TASK"] current_file = os.path.basename(context.data.get("currentFile")) name, ext = os.path.splitext(current_file) # get current file host - host = a_session["AVALON_APP"] - family = "projectfile" - families = "filesave" + family = "workfile" subset_name = "{0}{1}".format(task, 'Default') instance_name = "{0}_{1}_{2}".format(name, family, subset_name) # Set label - label = "{0} - {1} > {2}".format(name, task, families) + label = "{0} - {1}".format(name, task) # get project file instance Data - pf_instance = [inst for inst in instances_data - if inst.get("family", None) in 'projectfile'] - self.log.debug('pf_instance: {}'.format(pf_instance)) - # get working file into instance for publishing - instance = context.create_instance(instance_name) - if pf_instance: - instance.data.update(pf_instance[0]) - instance.data.update({ - "subset": subset_name, - "stagingDir": staging_dir, - "task": task, - "representation": ext[1:], - "host": host, - "asset": asset_name, - "label": label, - "name": name, - # "hierarchy": hierarchy, - # "parents": parents, - "family": family, - "families": [families, 'ftrack'], - "publish": True, - # "files": files_list - }) - instances.append(instance) + wf_instance = next((inst for inst in instances_data + if inst.get("family", None) in 'workfile'), None) + + if wf_instance: + self.log.debug('wf_instance: {}'.format(wf_instance)) + + version = int(wf_instance.get("version", None)) + # get working file into instance for publishing + instance = context.create_instance(instance_name) + instance.data.update(wf_instance) + + instance.data.update({ + "subset": subset_name, + "stagingDir": staging_dir, + "task": task, + "representations": [{ + "files": current_file, + 'stagingDir': staging_dir, + 'name': "projectfile", + 'ext': ext[1:] + }], + "host": host, + "asset": asset, + "label": label, + "name": name, + "family": family, + "families": ["ftrack"], + "publish": True, + "version": version + }) + instances.append(instance) for inst in instances_data: # for key, value in inst.items(): # self.log.debug('instance[key]: {}'.format(key)) # - version = inst.get("version", None) + version = int(inst.get("version", None)) assert version, "No `version` string in json file" name = asset = inst.get("name", None) @@ -135,14 +127,14 @@ def process(self, context): assert family, "No `family` key in json_data.instance: {}".format( inst) - if family in 'projectfile': + if family in 'workfile': continue files_list = inst.get("files", None) assert files_list, "`files` are empty in json file" hierarchy = inst.get("hierarchy", None) - assert hierarchy, "No `hierarchy` data in json file" + assert hierarchy, f"No `hierarchy` data in json file for {name}" parents = inst.get("parents", None) assert parents, "No `parents` data in json file" @@ -161,17 +153,12 @@ def process(self, context): # create list of tasks for creation if not inst.get('tasks', None): inst['tasks'] = list() - if not inst.get('tasksTypes', None): - inst['tasksTypes'] = {} # append taks into list for later hierarchy cration - ftrack_task_type = ftrack_types[task] if task not in inst['tasks']: inst['tasks'].append(task) - inst['tasksTypes'][task] = ftrack_task_type - host = rules_tasks["taskHost"][task] - subsets = rules_tasks["taskSubsets"][task] + subsets = rules_tasks["taskToSubsets"][task] for sub in subsets: self.log.debug(sub) try: @@ -184,8 +171,8 @@ def process(self, context): subset_lst.extend([s for s in subsets if s not in subset_lst]) for subset in subset_lst: - if inst["representations"].get(subset, None): - repr = inst["representations"][subset] + if inst["subsetToRepresentations"].get(subset, None): + repr = inst["subsetToRepresentations"][subset] ext = repr['representation'] else: continue @@ -197,7 +184,7 @@ def process(self, context): family = subset subset_name = "{0}{1}".format(subset, "Main") elif "reference" in subset: - family ="render" + family = "review" subset_name = "{0}{1}".format(family, "Reference") else: subset_name = "{0}{1}".format(subset, 'Default') @@ -209,17 +196,15 @@ def process(self, context): instance = context.create_instance(name) files = [f for f in files_list - if subset in f or "thumbnail" in f - ] + if subset in f or "thumbnail" in f] instance.data.update({ "subset": subset_name, "stagingDir": staging_dir, "tasks": subset_dict[subset], - "taskTypes": inst['tasksTypes'], - "fstart": frame_start, - "handles": handles, - "host": host, + "frameStart": frame_start, + "handleStart": handle_start, + "handleEnd": handle_end, "asset": asset, "hierarchy": hierarchy, "parents": parents, @@ -230,6 +215,8 @@ def process(self, context): "family": family, "families": [subset, inst["family"], 'ftrack'], "jsonData": inst, + "jsonReprSubset": subset, + "jsonReprExt": ext, "publish": True, "version": version}) self.log.info( @@ -238,9 +225,6 @@ def process(self, context): context.data["instances"] = instances - # Sort/grouped by family (preserving local index) - # context[:] = sorted(context, key=self.sort_by_task) - self.log.debug("context: {}".format(context)) def sort_by_task(self, instance): diff --git a/pype/plugins/aport/publish/extract_post_json.py b/pype/plugins/adobecommunicator/publish/extract_post_json.py similarity index 71% rename from pype/plugins/aport/publish/extract_post_json.py rename to pype/plugins/adobecommunicator/publish/extract_post_json.py index 0603bd4df35..c545e474752 100644 --- a/pype/plugins/aport/publish/extract_post_json.py +++ b/pype/plugins/adobecommunicator/publish/extract_post_json.py @@ -2,7 +2,7 @@ import json import clique import pyblish.api - +from pypeapp import Anatomy class ExtractJSON(pyblish.api.ContextPlugin): """ Extract all instances to a serialized json file. """ @@ -14,28 +14,27 @@ def process(self, context): json_path = context.data['post_json_data_path'] data = dict(self.serialize(context.data())) - # self.log.info(data) - - instances_data = [] - for instance in context: - - iData = {} - for key, value in instance.data.items(): - if isinstance(value, clique.Collection): - value = value.format() - - try: - json.dumps(value) - iData[key] = value - except KeyError: - msg = "\"{0}\"".format(value) - msg += " in instance.data[\"{0}\"]".format(key) - msg += " could not be serialized." - self.log.debug(msg) - instances_data.append(iData) - - data["instances"] = instances_data + # instances_data = [] + # for instance in context: + # + # iData = {} + # for key, value in instance.data.items(): + # if isinstance(value, clique.Collection): + # value = value.format() + # + # try: + # json.dumps(value) + # iData[key] = value + # except KeyError: + # msg = "\"{0}\"".format(value) + # msg += " in instance.data[\"{0}\"]".format(key) + # msg += " could not be serialized." + # self.log.debug(msg) + # + # instances_data.append(iData) + # + # data["instances"] = instances_data with open(json_path, "w") as outfile: outfile.write(json.dumps(data, indent=4, sort_keys=True)) @@ -60,6 +59,9 @@ def encoding_obj(value): # self.log.info("1: {}".format(data)) + if isinstance(data, Anatomy): + return + if not isinstance(data, dict): # self.log.info("2: {}".format(data)) return data @@ -88,6 +90,9 @@ def encoding_obj(value): # loops if dictionary data[key] = self.serialize(value) + if isinstance(value, Anatomy): + continue + if isinstance(value, (list or tuple)): # loops if list or tuple for i, item in enumerate(value): diff --git a/pype/plugins/aport/publish/collect_context.py b/pype/plugins/aport/publish/collect_context.py deleted file mode 100644 index 35811d63787..00000000000 --- a/pype/plugins/aport/publish/collect_context.py +++ /dev/null @@ -1,104 +0,0 @@ -import os -import pyblish.api -from avalon import api as avalon -from pype import api as pype -import json -from pathlib import Path - - -class CollectContextDataFromAport(pyblish.api.ContextPlugin): - """ - Collecting temp json data sent from a host context - and path for returning json data back to hostself. - - Setting avalon session into correct context - - Args: - context (obj): pyblish context session - - """ - - label = "Collect Aport Context" - order = pyblish.api.CollectorOrder - 0.49 - - def process(self, context): - - # get json paths from data - rqst_json_data_path = Path(context.data['rqst_json_data_path']) - post_json_data_path = Path(context.data['post_json_data_path']) - - # get avalon session data and convert \ to / - session = avalon.session - self.log.info(os.environ['AVALON_PROJECTS']) - projects = Path(session['AVALON_PROJECTS']).resolve() - wd = Path(session['AVALON_WORKDIR']).resolve() - session['AVALON_PROJECTS'] = str(projects) - session['AVALON_WORKDIR'] = str(wd) - - context.data["avalonSession"] = session - self.log.debug("avalonSession: {}".format(session)) - - # get stagin directory from recieved path to json - context.data["stagingDir"] = staging_dir = post_json_data_path.parent - - # get data from json file recieved - with rqst_json_data_path.open(mode='r') as f: - context.data['jsonData'] = json_data = json.load(f) - assert json_data, "No `data` in json file" - - # get and check host type - host = json_data.get("host", None) - host_version = json_data.get("hostVersion", None) - assert host, "No `host` data in json file" - assert host_version, "No `hostVersion` data in json file" - context.data["host"] = session["AVALON_APP"] = host - context.data["hostVersion"] = \ - session["AVALON_APP_VERSION"] = host_version - - # register pyblish for filtering of hosts in plugins - pyblish.api.deregister_all_hosts() - pyblish.api.register_host(host) - - # get path to studio templates - templates_dir = os.getenv("PYPE_STUDIO_TEMPLATES", None) - assert templates_dir, "Missing `PYPE_STUDIO_TEMPLATES` in os.environ" - - # get presets for host - presets_dir = os.path.join(templates_dir, "presets", host) - assert os.path.exists( - presets_dir), "Required path `{}` doesn't exist".format(presets_dir) - - # load all available preset json files - preset_data = dict() - for file in os.listdir(presets_dir): - name, ext = os.path.splitext(file) - with open(os.path.join(presets_dir, file)) as prst: - preset_data[name] = json.load(prst) - - context.data['presets'] = preset_data - assert preset_data, "No `presets` data in json file" - self.log.debug("preset_data: {}".format(preset_data)) - - # get current file - current_file = json_data.get("currentFile", None) - assert current_file, "No `currentFile` data in json file" - context.data["currentFile"] = Path(current_file).resolve() - - # get project data from avalon - project_data = pype.get_project_data() - assert project_data, "No `project_data` data in avalon db" - context.data["projectData"] = project_data - self.log.debug("project_data: {}".format(project_data)) - - # get asset data from avalon and fix all paths - asset_data = pype.get_asset_data() - assert asset_data, "No `asset_data` data in avalon db" - asset_data = {k: v.replace("\\", "/") for k, v in asset_data.items() - if isinstance(v, str)} - context.data["assetData"] = asset_data - - self.log.debug("asset_data: {}".format(asset_data)) - self.log.info("rqst_json_data_path is: {}".format(rqst_json_data_path)) - self.log.info("post_json_data_path is: {}".format(post_json_data_path)) - - # self.log.info("avalon.session is: {}".format(avalon.session)) diff --git a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py index 1deff56d837..a12fdfd36ca 100644 --- a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py +++ b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py @@ -89,7 +89,7 @@ def import_to_ftrack(self, input_data, parent=None): # CUSTOM ATTRIBUTES custom_attributes = entity_data.get('custom_attributes', []) instances = [ - i for i in self.context[:] if i.data['asset'] in entity['name'] + i for i in self.context if i.data['asset'] in entity['name'] ] for key in custom_attributes: assert (key in entity['custom_attributes']), ( diff --git a/pype/plugins/global/publish/extract_burnin.py b/pype/plugins/global/publish/extract_burnin.py index 7668eafd2a7..71917946b88 100644 --- a/pype/plugins/global/publish/extract_burnin.py +++ b/pype/plugins/global/publish/extract_burnin.py @@ -18,7 +18,7 @@ class ExtractBurnin(pype.api.Extractor): label = "Extract burnins" order = pyblish.api.ExtractorOrder + 0.03 families = ["review", "burnin"] - hosts = ["nuke", "maya", "shell"] + hosts = ["nuke", "maya", "shell", "premiere"] optional = True def process(self, instance): diff --git a/pype/plugins/global/publish/extract_review.py b/pype/plugins/global/publish/extract_review.py index 625c96566d4..b0db2423d44 100644 --- a/pype/plugins/global/publish/extract_review.py +++ b/pype/plugins/global/publish/extract_review.py @@ -20,7 +20,7 @@ class ExtractReview(pyblish.api.InstancePlugin): label = "Extract Review" order = pyblish.api.ExtractorOrder + 0.02 families = ["review"] - hosts = ["nuke", "maya", "shell"] + hosts = ["nuke", "maya", "shell", "premiere"] outputs = {} ext_filter = [] diff --git a/pype/plugins/global/publish/integrate_new.py b/pype/plugins/global/publish/integrate_new.py index 9eab1a15b13..9ea3d0bda9a 100644 --- a/pype/plugins/global/publish/integrate_new.py +++ b/pype/plugins/global/publish/integrate_new.py @@ -610,7 +610,7 @@ def get_subset(self, asset, instance): "name": subset_name, "data": { "families": instance.data.get('families') - }, + }, "parent": asset["_id"] }).inserted_id @@ -664,13 +664,17 @@ def create_version_data(self, context, instance): families += current_families self.log.debug("Registered root: {}".format(api.registered_root())) + # create relative source path for DB try: source = instance.data['source'] except KeyError: source = context.data["currentFile"] - source = source.replace(os.getenv("PYPE_STUDIO_PROJECTS_MOUNT"), - api.registered_root()) + self.log.debug("source: {}".format(source)) + source = str(source).replace( + os.getenv("PYPE_STUDIO_PROJECTS_MOUNT"), + api.registered_root() + ) relative_path = os.path.relpath(source, api.registered_root()) source = os.path.join("{root}", relative_path).replace("\\", "/") diff --git a/pype/plugins/premiere/publish/collect_audio_version.py b/pype/plugins/premiere/publish/collect_audio_version.py index 3e3522b9886..8c2aa68bddb 100644 --- a/pype/plugins/premiere/publish/collect_audio_version.py +++ b/pype/plugins/premiere/publish/collect_audio_version.py @@ -13,5 +13,5 @@ class CollectAudioVersion(pyblish.api.InstancePlugin): def process(self, instance): self.log.info('Audio: {}'.format(instance.data['name'])) - instance.data['version'] = '001' + instance.data['version'] = 1 self.log.info('Audio version to: {}'.format(instance.data['version'])) diff --git a/pype/plugins/premiere/publish/collect_context.py b/pype/plugins/premiere/publish/collect_context.py deleted file mode 100644 index e1bfdf0fa9e..00000000000 --- a/pype/plugins/premiere/publish/collect_context.py +++ /dev/null @@ -1,12 +0,0 @@ -import pyblish.api - - -class CollectContextDataPremiera(pyblish.api.ContextPlugin): - """Collecting data from temp json sent from premiera context""" - - label = "Collect Premiera Context" - order = pyblish.api.CollectorOrder + 0.1 - - def process(self, context): - data_path = context.data['rqst_json_data_path'] - self.log.info("Context is: {}".format(data_path)) diff --git a/pype/plugins/premiere/publish/collect_frameranges.py b/pype/plugins/premiere/publish/collect_frameranges.py index 2cf5b839384..ffcc1023b53 100644 --- a/pype/plugins/premiere/publish/collect_frameranges.py +++ b/pype/plugins/premiere/publish/collect_frameranges.py @@ -19,16 +19,18 @@ def process(self, instance): metadata = instance.data.get('jsonData').get('metadata') # getting important metadata time calculation - fps = metadata['ppro.timeline.fps'] + fps = float(metadata['ppro.timeline.fps']) sec_start = metadata['ppro.clip.start'] sec_end = metadata['ppro.clip.end'] - fstart = instance.data.get('fstart') + fstart = instance.data.get('frameStart') fend = fstart + (sec_end * fps) - (sec_start * fps) - 1 self.log.debug("instance: {}, fps: {}\nsec_start: {}\nsec_end: {}\nfstart: {}\nfend: {}\n".format( instance.data['name'], fps, sec_start, sec_end, fstart, fend)) - instance.data['startFrame'] = fstart - instance.data['endFrame'] = fend + instance.data['frameStart'] = fstart + instance.data['frameEnd'] = fend + instance.data['handleStart'] = instance.context.data['handleStart'] + instance.data['handleEnd'] = instance.context.data['handleEnd'] instance.data['fps'] = metadata['ppro.timeline.fps'] diff --git a/pype/plugins/premiere/publish/collect_hierarchy_context.py b/pype/plugins/premiere/publish/collect_hierarchy_context.py index b421d31f79d..1fdcd102027 100644 --- a/pype/plugins/premiere/publish/collect_hierarchy_context.py +++ b/pype/plugins/premiere/publish/collect_hierarchy_context.py @@ -26,7 +26,7 @@ def process(self, context): json_data = context.data.get("jsonData", None) temp_context = {} for instance in json_data['instances']: - if instance['family'] in 'projectfile': + if instance['family'] in 'workfile': continue in_info = {} @@ -35,10 +35,13 @@ def process(self, context): in_info['entity_type'] = 'Shot' instance_pyblish = [ - i for i in context.data["instances"] if i.data['asset'] in name][0] + i for i in context.data["instances"] + if i.data['asset'] in name][0] in_info['custom_attributes'] = { - 'fend': instance_pyblish.data['endFrame'], - 'fstart': instance_pyblish.data['startFrame'], + 'frameStart': instance_pyblish.data['frameStart'], + 'frameEnd': instance_pyblish.data['frameEnd'], + 'handleStart': instance_pyblish.data['handleStart'], + 'handleEnd': instance_pyblish.data['handleEnd'], 'fps': instance_pyblish.data['fps'] } diff --git a/pype/plugins/premiere/publish/collect_instance_representations.py b/pype/plugins/premiere/publish/collect_instance_representations.py new file mode 100644 index 00000000000..f53c60ad642 --- /dev/null +++ b/pype/plugins/premiere/publish/collect_instance_representations.py @@ -0,0 +1,83 @@ +import os +import pyblish.api + + +class CollectClipRepresentations(pyblish.api.InstancePlugin): + """ + Collecting frameranges needed for ftrack integration + + Args: + context (obj): pyblish context session + + """ + + label = "Collect Clip Representations" + order = pyblish.api.CollectorOrder + families = ['clip'] + + def process(self, instance): + # add to representations + if not instance.data.get("representations"): + instance.data["representations"] = list() + + ins_d = instance.data + staging_dir = ins_d["stagingDir"] + frame_start = ins_d["frameStart"] + frame_end = ins_d["frameEnd"] + handle_start = ins_d["handleStart"] + handle_end = ins_d["handleEnd"] + fps = ins_d["fps"] + files_list = ins_d.get("files") + + if not files_list: + return + + json_repr_ext = ins_d["jsonReprExt"] + json_repr_subset = ins_d["jsonReprSubset"] + + if files_list: + file = next((f for f in files_list + if json_repr_subset in f), None) + else: + return + + if json_repr_ext in ["mov", "mp4"]: + representation = { + "files": file, + "stagingDir": staging_dir, + "frameStart": frame_start, + "frameEnd": frame_end, + "frameStartFtrack": frame_start - handle_start, + "frameEndFtrack": frame_end - handle_end, + "step": 1, + "fps": fps, + "name": json_repr_subset, + "ext": json_repr_ext, + "tags": ["review", "delete"] + } + else: + representation = { + "files": file, + "stagingDir": staging_dir, + "step": 1, + "fps": fps, + "name": json_repr_subset, + "ext": json_repr_ext, + "tags": ["review"] + } + self.log.debug("representation: {}".format(representation)) + instance.data["representations"].append(representation) + + thumb = next((f for f in files_list + if "thumbnail" in f), None) + if thumb: + thumb_representation = { + 'files': thumb, + 'stagingDir': staging_dir, + 'name': "thumbnail", + 'thumbnail': True, + 'ext': os.path.splitext(thumb)[-1].replace(".", "") + } + self.log.debug("representation: {}".format(thumb_representation)) + instance.data["representations"].append( + thumb_representation) diff --git a/pype/plugins/premiere/publish/collect_resolution.py b/pype/plugins/premiere/publish/collect_resolution.py new file mode 100644 index 00000000000..d93dbf0b66e --- /dev/null +++ b/pype/plugins/premiere/publish/collect_resolution.py @@ -0,0 +1,31 @@ +import pyblish.api + + +class CollectResolution(pyblish.api.InstancePlugin): + """ + Collecting frameranges needed for ftrack integration + + Args: + context (obj): pyblish context session + + """ + + label = "Collect Clip Resolution" + order = pyblish.api.CollectorOrder + families = ['clip'] + + def process(self, instance): + # getting metadata from jsonData key + metadata = instance.data.get('jsonData').get('metadata') + + # getting important metadata time calculation + pixel_aspect = float(metadata['ppro.format.pixelaspect']) + res_width = metadata['ppro.format.width'] + res_height = metadata['ppro.format.height'] + + instance.data['pixelAspect'] = pixel_aspect + instance.data['resolutionWidth'] = res_width + instance.data['resolutionHeight'] = res_height + + self.log.info(f"Resolution was set to: `{res_width}x{res_height}`," + f" and pixel aspect ration to: `{pixel_aspect}`") diff --git a/pype/plugins/premiere/publish/integrate_assumed_destination.py b/pype/plugins/premiere/publish/integrate_assumed_destination.py deleted file mode 100644 index a0393e8a435..00000000000 --- a/pype/plugins/premiere/publish/integrate_assumed_destination.py +++ /dev/null @@ -1,144 +0,0 @@ -import pyblish.api -import os - -from avalon import io, api - - -class IntegrateAssumedDestination(pyblish.api.InstancePlugin): - """Generate the assumed destination path where the file will be stored""" - - label = "Integrate Assumed Destination" - order = pyblish.api.IntegratorOrder - 0.05 - families = ["clip", "projectfile"] - - def process(self, instance): - - self.create_destination_template(instance) - - template_data = instance.data["assumedTemplateData"] - # template = instance.data["template"] - - anatomy = instance.context.data['anatomy'] - # template = anatomy.publish.path - anatomy_filled = anatomy.format(template_data) - mock_template = anatomy_filled.publish.path - - # For now assume resources end up in a "resources" folder in the - # published folder - mock_destination = os.path.join(os.path.dirname(mock_template), - "resources") - - # Clean the path - mock_destination = os.path.abspath(os.path.normpath(mock_destination)) - - # Define resource destination and transfers - resources = instance.data.get("resources", list()) - transfers = instance.data.get("transfers", list()) - for resource in resources: - - # Add destination to the resource - source_filename = os.path.basename(resource["source"]) - destination = os.path.join(mock_destination, source_filename) - - # Force forward slashes to fix issue with software unable - # to work correctly with backslashes in specific scenarios - # (e.g. escape characters in PLN-151 V-Ray UDIM) - destination = destination.replace("\\", "/") - - resource['destination'] = destination - - # Collect transfers for the individual files of the resource - # e.g. all individual files of a cache or UDIM textures. - files = resource['files'] - for fsrc in files: - fname = os.path.basename(fsrc) - fdest = os.path.join(mock_destination, fname) - transfers.append([fsrc, fdest]) - - instance.data["resources"] = resources - instance.data["transfers"] = transfers - - def create_destination_template(self, instance): - """Create a filepath based on the current data available - - Example template: - {root}/{project}/{silo}/{asset}/publish/{subset}/v{version:0>3}/ - {subset}.{representation} - Args: - instance: the instance to publish - - Returns: - file path (str) - """ - - # get all the stuff from the database - subset_name = instance.data["subset"] - self.log.info(subset_name) - asset_name = instance.data["asset"] - project_name = api.Session["AVALON_PROJECT"] - - project = io.find_one( - { - "type": "project", - "name": project_name - }, - projection={"config": True, "data": True} - ) - - template = project["config"]["template"]["publish"] - # anatomy = instance.context.data['anatomy'] - - asset = io.find_one({ - "type": "asset", - "name": asset_name, - "parent": project["_id"] - }) - - assert asset, ("No asset found by the name '{}' " - "in project '{}'".format(asset_name, project_name)) - silo = asset.get('silo') - - subset = io.find_one({ - "type": "subset", - "name": subset_name, - "parent": asset["_id"] - }) - - # assume there is no version yet, we start at `1` - version = None - version_number = 1 - if subset is not None: - version = io.find_one( - { - "type": "version", - "parent": subset["_id"] - }, - sort=[("name", -1)] - ) - - # if there is a subset there ought to be version - if version is not None: - version_number += version["name"] - - if instance.data.get('version'): - version_number = int(instance.data.get('version')) - - hierarchy = asset['data']['parents'] - if hierarchy: - # hierarchy = os.path.sep.join(hierarchy) - hierarchy = os.path.join(*hierarchy) - - template_data = {"root": api.Session["AVALON_PROJECTS"], - "project": {"name": project_name, - "code": project['data']['code']}, - "silo": silo, - "family": instance.data['family'], - "asset": asset_name, - "subset": subset_name, - "version": version_number, - "hierarchy": hierarchy, - "representation": "TEMP"} - - instance.data["assumedTemplateData"] = template_data - self.log.info(template_data) - instance.data["template"] = template diff --git a/pype/plugins/premiere/publish/integrate_hierarchy_avalon.py b/pype/plugins/premiere/publish/integrate_hierarchy_avalon.py deleted file mode 100644 index 0f7fdb20d32..00000000000 --- a/pype/plugins/premiere/publish/integrate_hierarchy_avalon.py +++ /dev/null @@ -1,140 +0,0 @@ -import pyblish.api -from avalon import io - - -class IntegrateHierarchyToAvalon(pyblish.api.ContextPlugin): - """ - Create entities in ftrack based on collected data from premiere - - """ - - order = pyblish.api.IntegratorOrder - 0.1 - label = 'Integrate Hierarchy To Avalon' - families = ['clip'] - - def process(self, context): - if "hierarchyContext" not in context.data: - return - - self.db = io - if not self.db.Session: - self.db.install() - - input_data = context.data["hierarchyContext"] - self.import_to_avalon(input_data) - - def import_to_avalon(self, input_data, parent=None): - - for name in input_data: - self.log.info('input_data[name]: {}'.format(input_data[name])) - entity_data = input_data[name] - entity_type = entity_data['entity_type'] - - data = {} - # Process project - if entity_type.lower() == 'project': - entity = self.db.find_one({'type': 'project'}) - # TODO: should be in validator? - assert (entity is not None), "Didn't find project in DB" - - # get data from already existing project - for key, value in entity.get('data', {}).items(): - data[key] = value - - self.av_project = entity - # Raise error if project or parent are not set - elif self.av_project is None or parent is None: - raise AssertionError( - "Collected items are not in right order!" - ) - # Else process assset - else: - entity = self.db.find_one({'type': 'asset', 'name': name}) - # Create entity if doesn't exist - if entity is None: - if self.av_project['_id'] == parent['_id']: - silo = None - elif parent['silo'] is None: - silo = parent['name'] - else: - silo = parent['silo'] - entity = self.create_avalon_asset(name, silo) - self.log.info('entity: {}'.format(entity)) - self.log.info('data: {}'.format(entity.get('data', {}))) - self.log.info('____1____') - data['entityType'] = entity_type - # TASKS - tasks = entity_data.get('tasks', []) - if tasks is not None or len(tasks) > 0: - data['tasks'] = tasks - parents = [] - visualParent = None - data = input_data[name] - if self.av_project['_id'] != parent['_id']: - visualParent = parent['_id'] - parents.extend(parent.get('data', {}).get('parents', [])) - parents.append(parent['name']) - data['visualParent'] = visualParent - data['parents'] = parents - - self.db.update_many( - {'_id': entity['_id']}, - {'$set': { - 'data': data, - }}) - - entity = self.db.find_one({'type': 'asset', 'name': name}) - self.log.info('entity: {}'.format(entity)) - self.log.info('data: {}'.format(entity.get('data', {}))) - self.log.info('____2____') - - # Else get data from already existing - else: - self.log.info('entity: {}'.format(entity)) - self.log.info('data: {}'.format(entity.get('data', {}))) - self.log.info('________') - for key, value in entity.get('data', {}).items(): - data[key] = value - - data['entityType'] = entity_type - # TASKS - tasks = entity_data.get('tasks', []) - if tasks is not None or len(tasks) > 0: - data['tasks'] = tasks - parents = [] - visualParent = None - # do not store project's id as visualParent (silo asset) - - if self.av_project['_id'] != parent['_id']: - visualParent = parent['_id'] - parents.extend(parent.get('data', {}).get('parents', [])) - parents.append(parent['name']) - data['visualParent'] = visualParent - data['parents'] = parents - - # CUSTOM ATTRIBUTES - for k, val in entity_data.get('custom_attributes', {}).items(): - data[k] = val - - # Update entity data with input data - self.db.update_many( - {'_id': entity['_id']}, - {'$set': { - 'data': data, - }}) - - if 'childs' in entity_data: - self.import_to_avalon(entity_data['childs'], entity) - - def create_avalon_asset(self, name, silo): - item = { - 'schema': 'avalon-core:asset-2.0', - 'name': name, - 'silo': silo, - 'parent': self.av_project['_id'], - 'type': 'asset', - 'data': {} - } - entity_id = self.db.insert_one(item).inserted_id - - return self.db.find_one({'_id': entity_id}) diff --git a/pype/plugins/premiere/publish/integrate_hierarchy_ftrack.py b/pype/plugins/premiere/publish/integrate_hierarchy_ftrack.py deleted file mode 100644 index c32df636e1a..00000000000 --- a/pype/plugins/premiere/publish/integrate_hierarchy_ftrack.py +++ /dev/null @@ -1,171 +0,0 @@ -import sys -import pyblish.api -import six - - -class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): - """ - Create entities in ftrack based on collected data from premiere - Example of entry data: - { - "ProjectXS": { - "entity_type": "Project", - "custom_attributes": { - "fps": 24,... - }, - "tasks": [ - "Compositing", - "Lighting",... *task must exist as task type in project schema* - ], - "childs": { - "sq01": { - "entity_type": "Sequence", - ... - } - } - } - } - """ - - order = pyblish.api.IntegratorOrder - label = 'Integrate Hierarchy To Ftrack' - families = ["clip"] - optional = False - - def process(self, context): - self.context = context - if "hierarchyContext" not in context.data: - return - - self.ft_project = None - self.session = context.data["ftrackSession"] - - input_data = context.data["hierarchyContext"] - - # adding ftrack types from presets - ftrack_types = context.data['ftrackTypes'] - - self.import_to_ftrack(input_data, ftrack_types) - - def import_to_ftrack(self, input_data, ftrack_types, parent=None): - for entity_name in input_data: - entity_data = input_data[entity_name] - entity_type = entity_data['entity_type'].capitalize() - - if entity_type.lower() == 'project': - query = 'Project where full_name is "{}"'.format(entity_name) - entity = self.session.query(query).one() - self.ft_project = entity - self.task_types = self.get_all_task_types(entity) - - elif self.ft_project is None or parent is None: - raise AssertionError( - "Collected items are not in right order!" - ) - - # try to find if entity already exists - else: - query = '{} where name is "{}" and parent_id is "{}"'.format( - entity_type, entity_name, parent['id'] - ) - try: - entity = self.session.query(query).one() - except Exception: - entity = None - - # Create entity if not exists - if entity is None: - entity = self.create_entity( - name=entity_name, - type=entity_type, - parent=parent - ) - # self.log.info('entity: {}'.format(dict(entity))) - # CUSTOM ATTRIBUTES - custom_attributes = entity_data.get('custom_attributes', []) - instances = [ - i for i in self.context.data["instances"] if i.data['asset'] in entity['name']] - for key in custom_attributes: - assert (key in entity['custom_attributes']), ( - 'Missing custom attribute') - - entity['custom_attributes'][key] = custom_attributes[key] - for instance in instances: - instance.data['ftrackShotId'] = entity['id'] - - try: - self.session.commit() - except Exception: - tp, value, tb = sys.exc_info() - self.session.rollback() - six.reraise(tp, value, tb) - - # TASKS - tasks = entity_data.get('tasks', []) - existing_tasks = [] - tasks_to_create = [] - for child in entity['children']: - if child.entity_type.lower() == 'task': - existing_tasks.append(child['name']) - # existing_tasks.append(child['type']['name']) - - for task in tasks: - if task in existing_tasks: - print("Task {} already exists".format(task)) - continue - tasks_to_create.append(task) - - for task in tasks_to_create: - self.create_task( - name=task, - task_type=ftrack_types[task], - parent=entity - ) - - if 'childs' in entity_data: - self.import_to_ftrack( - entity_data['childs'], ftrack_types, entity) - - def get_all_task_types(self, project): - tasks = {} - proj_template = project['project_schema'] - temp_task_types = proj_template['_task_type_schema']['types'] - - for type in temp_task_types: - if type['name'] not in tasks: - tasks[type['name']] = type - - return tasks - - def create_task(self, name, task_type, parent): - task = self.session.create('Task', { - 'name': name, - 'parent': parent - }) - # TODO not secured!!! - check if task_type exists - self.log.info(task_type) - self.log.info(self.task_types) - task['type'] = self.task_types[task_type] - - try: - self.session.commit() - except Exception: - tp, value, tb = sys.exc_info() - self.session.rollback() - six.reraise(tp, value, tb) - - return task - - def create_entity(self, name, type, parent): - entity = self.session.create(type, { - 'name': name, - 'parent': parent - }) - try: - self.session.commit() - except Exception: - tp, value, tb = sys.exc_info() - self.session.rollback() - six.reraise(tp, value, tb) - - return entity diff --git a/pype/premiere/__init__.py b/pype/premiere/__init__.py index 287f07f433d..9dfe2ec3842 100644 --- a/pype/premiere/__init__.py +++ b/pype/premiere/__init__.py @@ -1,160 +1,71 @@ import os -import sys -import shutil - -from pysync import walktree - from avalon import api as avalon -from avalon.lib import launch from pyblish import api as pyblish -from app import api as app -from pprint import pprint -from .. import api - - -import requests - - -log = api.Logger.getLogger(__name__, "premiere") - -AVALON_CONFIG = os.getenv("AVALON_CONFIG", "pype") -EXTENSIONS_PATH_LOCAL = os.getenv("EXTENSIONS_PATH", None) -EXTENSIONS_CACHE_PATH = os.getenv("EXTENSIONS_CACHE_PATH", None) -EXTENSIONS_PATH_REMOTE = os.path.join(os.path.dirname(__file__), "extensions") -PARENT_DIR = os.path.dirname(__file__) -PACKAGE_DIR = os.path.dirname(PARENT_DIR) -PLUGINS_DIR = os.path.join(PACKAGE_DIR, "plugins") - -_clearing_cache = ["com.pype.rename", "com.pype.avalon"] - -PUBLISH_PATH = os.path.join( - PLUGINS_DIR, "premiere", "publish" -).replace("\\", "/") - -if os.getenv("PUBLISH_PATH", None): - os.environ["PUBLISH_PATH"] = os.pathsep.join( - os.environ["PUBLISH_PATH"].split(os.pathsep) + - [PUBLISH_PATH] - ) -else: - os.environ["PUBLISH_PATH"] = PUBLISH_PATH - -LOAD_PATH = os.path.join(PLUGINS_DIR, "premiere", "load") -CREATE_PATH = os.path.join(PLUGINS_DIR, "premiere", "create") -INVENTORY_PATH = os.path.join(PLUGINS_DIR, "premiere", "inventory") - -def clearing_caches_ui(): - '''Before every start of premiere it will make sure there is not - outdated stuff in cep_cache dir''' - - for d in os.listdir(EXTENSIONS_CACHE_PATH): - match = [p for p in _clearing_cache - if str(p) in d] - - if match: - try: - path = os.path.normpath(os.path.join(EXTENSIONS_CACHE_PATH, d)) - log.info("Removing dir: {}".format(path)) - shutil.rmtree(path, ignore_errors=True) - except Exception as e: - log.debug("problem: {}".format(e)) - -def request_aport(url_path, data={}): - try: - api.add_tool_to_environment(["aport_0.1"]) - - ip = os.getenv("PICO_IP", None) - if ip and ip.startswith('http'): - ip = ip.replace("http://", "") - - port = int(os.getenv("PICO_PORT", None)) - - url = "http://{0}:{1}{2}".format(ip, port, url_path) - req = requests.post(url, data=data).text - return req - - except Exception as e: - api.message(title="Premiere Aport Server", - message="Before you can run Premiere, start Aport Server. \n Error: {}".format( - e), - level="critical") - - -def extensions_sync(): - # import time - process_pairs = list() - # get extensions dir in pype.premiere.extensions - # build dir path to premiere cep extensions - for name in os.listdir(EXTENSIONS_PATH_REMOTE): - print(name) - src = os.path.join(EXTENSIONS_PATH_REMOTE, name) - dst = os.path.join(EXTENSIONS_PATH_LOCAL, name) - process_pairs.append((name, src, dst)) - - # synchronize all extensions - for name, src, dst in process_pairs: - if not os.path.exists(dst): - os.makedirs(dst, mode=0o777) - walktree(source=src, target=dst, options_input=["y", ">"]) - log.info("Extension {0} from `{1}` coppied to `{2}`".format( - name, src, dst - )) - # time.sleep(10) - return +from pypeapp import Logger -def install(): - api.set_avalon_workdir() - log.info("Registering Premiera plug-ins..") - reg_paths = request_aport("/api/register_plugin_path", - {"publish_path": PUBLISH_PATH}) +from .lib import ( + setup, + reload_pipeline, + ls, + LOAD_PATH, + CREATE_PATH, + PUBLISH_PATH +) - # avalon.register_plugin_path(avalon.Loader, LOAD_PATH) - # avalon.register_plugin_path(avalon.Creator, CREATE_PATH) - # avalon.register_plugin_path(avalon.InventoryAction, INVENTORY_PATH) +__all__ = [ + "setup", + "reload_pipeline", + "ls" +] - # Disable all families except for the ones we explicitly want to see - # family_states = [ - # "imagesequence", - # "mov" - # - # ] - # avalon.data["familiesStateDefault"] = False - # avalon.data["familiesStateToggled"] = family_states +log = Logger().get_logger(__name__, "premiere") - # load data from templates - api.load_data_from_templates() - # remove cep_cache from user temp dir - clearing_caches_ui() +def install(): + """Install Premiere-specific functionality of avalon-core. + + This is where you install menus and register families, data + and loaders into Premiere. - # synchronize extensions - extensions_sync() - message = "The Pype extension has been installed. " \ - "\nThe following publishing paths has been registered: " \ - "\n\n{}".format( - reg_paths) + It is called automatically when installing via `api.install(premiere)`. - api.message(title="pyblish_paths", message=message, level="info") + See the Maya equivalent for inspiration on how to implement this. - # launching premiere - exe = r"C:\Program Files\Adobe\Adobe Premiere Pro CC 2019\Adobe Premiere Pro.exe".replace( - "\\", "/") + """ - log.info("____path exists: {}".format(os.path.exists(exe))) + # Disable all families except for the ones we explicitly want to see + family_states = [ + "imagesequence", + "mov" + ] + avalon.data["familiesStateDefault"] = False + avalon.data["familiesStateToggled"] = family_states - app.forward(args=[exe], - silent=False, - cwd=os.getcwd(), - env=dict(os.environ), - shell=None) + log.info("pype.premiere installed") + + pyblish.register_host("premiere") + pyblish.register_plugin_path(PUBLISH_PATH) + log.info("Registering Premiera plug-ins..") + + avalon.register_plugin_path(avalon.Loader, LOAD_PATH) + avalon.register_plugin_path(avalon.Creator, CREATE_PATH) def uninstall(): - log.info("Deregistering Premiera plug-ins..") + """Uninstall all tha was installed + + This is where you undo everything that was done in `install()`. + That means, removing menus, deregistering families and data + and everything. It should be as though `install()` was never run, + because odds are calling this function means the user is interested + in re-installing shortly afterwards. If, for example, he has been + modifying the menu or registered families. + + """ + pyblish.deregister_host("premiere") pyblish.deregister_plugin_path(PUBLISH_PATH) + log.info("Deregistering Premiera plug-ins..") + avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH) avalon.deregister_plugin_path(avalon.Creator, CREATE_PATH) - - # reset data from templates - api.reset_data_from_templates() diff --git a/pype/premiere/extensions/build_extension.bat b/pype/premiere/extensions/build_extension.bat new file mode 100644 index 00000000000..4fcee96d211 --- /dev/null +++ b/pype/premiere/extensions/build_extension.bat @@ -0,0 +1,20 @@ +@echo off +rem You need https://github.com/Adobe-CEP/CEP-Resources/raw/master/ZXPSignCMD/4.1.1/win64/ZXPSignCmd.exe + +rem You need https://partners.adobe.com/exchangeprogram/creativecloud/support/exman-com-line-tool.html + +rem !!! make sure you run windows power shell as admin + +set pwd="12PPROext581" + +echo ">>> creating certificate ..." +.\ZXPSignCmd -selfSignedCert CZ Prague OrbiTools "Signing robot" %pwd% certificate.p12 +echo ">>> building com.pype" +.\ZXPSignCmd -sign com.pype/ pype.zxp certificate.p12 %pwd% +echo ">>> building com.pype.rename" +.\ZXPSignCmd -sign com.pype.rename/ pype_rename.zxp certificate.p12 %pwd% + +echo ">>> installing com.pype" +.\ExManCmd.exe /install .\pype.zxp +echo ">>> installing com.pype.rename" +.\ExManCmd.exe /install .\pype_rename.zxp diff --git a/pype/premiere/extensions/com.pype.avalon/.debug b/pype/premiere/extensions/com.pype.avalon/.debug deleted file mode 100644 index 3f19d536999..00000000000 --- a/pype/premiere/extensions/com.pype.avalon/.debug +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/pype/premiere/extensions/com.pype.avalon/index_remote.html b/pype/premiere/extensions/com.pype.avalon/index_remote.html deleted file mode 100644 index 01226ca42d1..00000000000 --- a/pype/premiere/extensions/com.pype.avalon/index_remote.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - Avalon - - - - - - - - - - - \ No newline at end of file diff --git a/pype/premiere/extensions/com.pype.avalon/jsx/PPRO/PPro_API_Constants.jsx b/pype/premiere/extensions/com.pype.avalon/jsx/PPRO/PPro_API_Constants.jsx deleted file mode 100644 index 17524d69689..00000000000 --- a/pype/premiere/extensions/com.pype.avalon/jsx/PPRO/PPro_API_Constants.jsx +++ /dev/null @@ -1,60 +0,0 @@ -/************************************************************************* -* ADOBE CONFIDENTIAL -* ___________________ -* -* Copyright 2014 Adobe -* All Rights Reserved. -* -* NOTICE: Adobe permits you to use, modify, and distribute this file in -* accordance with the terms of the Adobe license agreement accompanying -* it. If you have received this file from a source other than Adobe, -* then your use, modification, or distribution of it requires the prior -* written permission of Adobe. -**************************************************************************/ -// time display types - -TIMEDISPLAY_24Timecode = 100; -TIMEDISPLAY_25Timecode = 101; -TIMEDISPLAY_2997DropTimecode = 102; -TIMEDISPLAY_2997NonDropTimecode = 103; -TIMEDISPLAY_30Timecode = 104; -TIMEDISPLAY_50Timecode = 105; -TIMEDISPLAY_5994DropTimecode = 106; -TIMEDISPLAY_5994NonDropTimecode = 107; -TIMEDISPLAY_60Timecode = 108; -TIMEDISPLAY_Frames = 109; -TIMEDISPLAY_23976Timecode = 110; -TIMEDISPLAY_16mmFeetFrames = 111; -TIMEDISPLAY_35mmFeetFrames = 112; -TIMEDISPLAY_48Timecode = 113; -TIMEDISPLAY_AudioSamplesTimecode = 200; -TIMEDISPLAY_AudioMsTimecode = 201; - -// field type constants - -FIELDTYPE_Progressive = 0; -FIELDTYPE_UpperFirst = 1; -FIELDTYPE_LowerFirst = 2; - -// audio channel types - -AUDIOCHANNELTYPE_Mono = 0; -AUDIOCHANNELTYPE_Stereo = 1; -AUDIOCHANNELTYPE_51 = 2; -AUDIOCHANNELTYPE_Multichannel = 3; -AUDIOCHANNELTYPE_4Channel = 4; -AUDIOCHANNELTYPE_8Channel = 5; - -// vr projection type - -VRPROJECTIONTYPE_None = 0; -VRPROJECTIONTYPE_Equirectangular = 1; - -// vr stereoscopic type - -VRSTEREOSCOPICTYPE_Monoscopic = 0; -VRSTEREOSCOPICTYPE_OverUnder = 1; -VRSTEREOSCOPICTYPE_SideBySide = 2; - -NOT_SET = -400000; - diff --git a/pype/premiere/extensions/com.pype.avalon/jsx/PPRO/Premiere.jsx b/pype/premiere/extensions/com.pype.avalon/jsx/PPRO/Premiere.jsx deleted file mode 100644 index 3318615a3b9..00000000000 --- a/pype/premiere/extensions/com.pype.avalon/jsx/PPRO/Premiere.jsx +++ /dev/null @@ -1,2383 +0,0 @@ -/************************************************************************* - * ADOBE CONFIDENTIAL - * ___________________ - * - * Copyright 2014 Adobe - * All Rights Reserved. - * - * NOTICE: Adobe permits you to use, modify, and distribute this file in - * accordance with the terms of the Adobe license agreement accompanying - * it. If you have received this file from a source other than Adobe, - * then your use, modification, or distribution of it requires the prior - * written permission of Adobe. - **************************************************************************/ -#include "PPro_API_Constants.jsx" - -$._PPP_ = { - - createDeepFolderStructure: function (foldersArray, maxDepth) { - if (typeof foldersArray !== 'object' || foldersArray.length <= 0) { - throw new Error('No valid folders array was provided!'); - } - - // if the first folder already exists, throw error - for (var i = 0; i < app.project.rootItem.children.numItems; i++) { - var curChild = app.project.rootItem.children[i]; - if (curChild.type === ProjectItemType.BIN && curChild.name === foldersArray[0]) { - throw new Error('Folder with name "' + curChild.name + '" already exists!'); - } - } - - // create the deep folder structure - var currentBin = app.project.rootItem.createBin(foldersArray[0]); - for (var m = 1; m < foldersArray.length && m < maxDepth; i++) { - currentBin = currentBin.createBin(foldersArray[i]); - } - }, - - getVersionInfo: function () { - return 'PPro ' + app.version + 'x' + app.build; - }, - - getUserName: function () { - var homeDir = new File('~/'); - var userName = homeDir.displayName; - homeDir.close(); - return userName; - }, - - keepPanelLoaded: function () { - app.setExtensionPersistent("com.pype.RenameDialog", 0); // 0, while testing (to enable rapid reload); 1 for "Never unload me, even when not visible." - }, - - updateGrowingFile: function () { - var numItems = app.project.rootItem.children.numItems; - for (var i = 0; i < numItems; i++) { - var currentItem = app.project.rootItem.children[i]; - if (currentItem) { - currentItem.refreshMedia(); - } - } - }, - - getSep: function () { - if (Folder.fs == 'Macintosh') { - return '/'; - } else { - return '\\'; - } - }, - - saveProject: function () { - app.project.save(); - }, - - exportCurrentFrameAsPNG: function () { - app.enableQE(); - var activeSequence = qe.project.getActiveSequence(); // note: make sure a sequence is active in PPro UI - if (activeSequence) { - // Create a file name based on timecode of frame. - var time = activeSequence.CTI.timecode; // CTI = Current Time Indicator. - var removeThese = /:|;/ig; // Why? Because Windows chokes on colons. - var time_nice = time.replace(removeThese, '_'); - var outputPath = new File("~/Desktop"); - var outputFileName = outputPath.fsName + $._PPP_.getSep() + time_nice + '___' + activeSequence.name; - var expPNG = activeSequence.exportFramePNG(time, outputFileName); - } else { - $._PPP_.updateEventPanel("No active sequence."); - } - }, - - renameFootage: function () { - var item = app.project.rootItem.children[0]; // assumes the zero-th item in the project is footage. - if (item) { - item.name = item.name + ", updated by PProPanel."; - } else { - $._PPP_.updateEventPanel("No project items found."); - } - }, - - getActiveSequenceName: function () { - if (app.project.activeSequence) { - return app.project.activeSequence.name; - } else { - return "No active sequence."; - } - }, - - projectPanelSelectionChanged: function (projectItems, viewID) { - - var remainingArgs = projectItems.length; - var message = ""; - - if (remainingArgs) { - var message = remainingArgs + " items selected: "; - var view = viewID; - - // Concatenate selected project item names, into message. - for (var i = 0; i < projectItems.length; i++) { - message += projectItems[i].name; - remainingArgs--; - if (remainingArgs > 1) { - message += ', '; - } - if (remainingArgs === 1) { - message += ", and "; - } - if (remainingArgs === 0) { - message += "."; - } - } - } else { - message = '0 items selected.'; - } - app.setSDKEventMessage(message, 'info'); - }, - - registerProjectPanelSelectionChangedFxn: function () { - var success = app.bind("onSourceClipSelectedInProjectPanel", $._PPP_.projectPanelSelectionChanged); - }, - - saveCurrentProjectLayout: function () { - var currentProjPanelDisplay = app.project.getProjectPanelMetadata(); - if (currentProjPanelDisplay) { - var outFileName = 'Previous_Project_Panel_Display_Settings.xml'; - var actualProjectPath = new File(app.project.path); - var projDir = actualProjectPath.parent; - if (actualProjectPath) { - var completeOutputPath = projDir + $._PPP_.getSep() + outFileName; - var outFile = new File(completeOutputPath); - if (outFile) { - outFile.encoding = "UTF8"; - outFile.open("w", "TEXT", "????"); - outFile.write(currentProjPanelDisplay); - $._PPP_.updateEventPanel("Saved layout to next to the project."); - outFile.close(); - } - actualProjectPath.close(); - } - } else { - $._PPP_.updateEventPanel("Could not retrieve current project layout."); - } - }, - - setProjectPanelMeta: function () { - var filterString = ""; - if (Folder.fs === 'Windows') { - filterString = "XML files:*.xml"; - } - var fileToOpen = File.openDialog("Choose Project panel layout to open.", - filterString, - false); - if (fileToOpen) { - if (fileToOpen.fsName.indexOf('.xml')) { // We should really be more careful, but hey, it says it's XML! - fileToOpen.encoding = "UTF8"; - fileToOpen.open("r", "TEXT", "????"); - var fileContents = fileToOpen.read(); - if (fileContents) { - var setResult = app.project.setProjectPanelMetadata(fileContents); - if (setResult) { - $._PPP_.updateEventPanel("Could not update layout using " + fileToOpen.filename + "."); - } else { - $._PPP_.updateEventPanel("Updated layout from .xml file."); - } - } - } - } else { - $._PPP_.updateEventPanel("No valid layout file chosen."); - } - }, - - exportSequenceAsPrProj: function () { - var activeSequence = app.project.activeSequence; - if (activeSequence) { - var startTimeOffset = activeSequence.zeroPoint; - var prProjExtension = '.prproj'; - var outputName = activeSequence.name; - var outFolder = Folder.selectDialog(); - - if (outFolder) { - var completeOutputPath = outFolder.fsName + - $._PPP_.getSep() + - outputName + - prProjExtension; - - app.project.activeSequence.exportAsProject(completeOutputPath); - - $._PPP_.updateEventPanel("Exported " + app.project.activeSequence.name + " to " + completeOutputPath + "."); - } else { - $._PPP_.updateEventPanel("Could not find or create output folder."); - } - - // Here's how to import N sequences from a project. - // - // var seqIDsToBeImported = new Array; - // seqIDsToBeImported[0] = ID1; - // ... - // seqIDsToBeImported[N] = IDN; - // - //app.project.importSequences(pathToPrProj, seqIDsToBeImported); - - } else { - $._PPP_.updateEventPanel("No active sequence."); - } - }, - - createSequenceMarkers: function () { - var activeSequence = app.project.activeSequence; - if (activeSequence) { - var markers = activeSequence.markers; - if (markers) { - var numMarkers = markers.numMarkers; - if (numMarkers > 0) { - var marker_index = 1; - for (var current_marker = markers.getFirstMarker(); current_marker !== undefined; current_marker = markers.getNextMarker(current_marker)) { - if (current_marker.name !== "") { - $._PPP_.updateEventPanel('Marker ' + marker_index + ' name = ' + current_marker.name + '.'); - } else { - $._PPP_.updateEventPanel('Marker ' + marker_index + ' has no name.'); - } - - if (current_marker.end.seconds > 0) { - $._PPP_.updateEventPanel('Marker ' + marker_index + ' duration = ' + (current_marker.end.seconds - current_marker.start.seconds) + ' seconds.'); - } else { - $._PPP_.updateEventPanel('Marker ' + marker_index + ' has no duration.'); - } - $._PPP_.updateEventPanel('Marker ' + marker_index + ' starts at ' + current_marker.start.seconds + ' seconds.'); - marker_index = marker_index + 1; - } - } - } - - var newCommentMarker = markers.createMarker(12.345); - newCommentMarker.name = 'Marker created by PProPanel.'; - newCommentMarker.comments = 'Here are some comments, inserted by PProPanel.'; - newCommentMarker.end = 15.6789; - - var newWebMarker = markers.createMarker(14.345); - newWebMarker.name = 'Web marker created by PProPanel.'; - newWebMarker.comments = 'Here are some comments, inserted by PProPanel.'; - newWebMarker.end = 17.6789; - newWebMarker.setTypeAsWebLink("http://www.adobe.com", "frame target"); - } else { - $._PPP_.updateEventPanel("No active sequence."); - } - }, - - exportFCPXML: function () { - if (app.project.activeSequence) { - var projPath = new File(app.project.path); - var parentDir = projPath.parent; - var outputName = app.project.activeSequence.name; - var xmlExtension = '.xml'; - var outputPath = Folder.selectDialog("Choose the output directory"); - - if (outputPath) { - var completeOutputPath = outputPath.fsName + $._PPP_.getSep() + outputName + xmlExtension; - app.project.activeSequence.exportAsFinalCutProXML(completeOutputPath, 1); // 1 == suppress UI - var info = "Exported FCP XML for " + - app.project.activeSequence.name + - " to " + - completeOutputPath + - "."; - $._PPP_.updateEventPanel(info); - } else { - $._PPP_.updateEventPanel("No output path chosen."); - } - } else { - $._PPP_.updateEventPanel("No active sequence."); - } - }, - - openInSource: function () { - var filterString = ""; - if (Folder.fs === 'Windows') { - filterString = "All files:*.*"; - } - var fileToOpen = File.openDialog("Choose file to open.", - filterString, - false); - if (fileToOpen) { - app.sourceMonitor.openFilePath(fileToOpen.fsName); - app.sourceMonitor.play(1.73); // playback speed as float, 1.0 = normal speed forward - var position = app.sourceMonitor.getPosition(); // new in 13.0 - $._PPP_.updateEventPanel("Current Source monitor position: " + position.seconds + " seconds."); - fileToOpen.close(); - } else { - $._PPP_.updateEventPanel("No file chosen."); - } - }, - - searchForBinWithName: function (nameToFind) { - // deep-search a folder by name in project - var deepSearchBin = function (inFolder) { - if (inFolder && inFolder.name === nameToFind && inFolder.type === 2) { - return inFolder; - } else { - for (var i = 0; i < inFolder.children.numItems; i++) { - if (inFolder.children[i] && inFolder.children[i].type === 2) { - var foundBin = deepSearchBin(inFolder.children[i]); - if (foundBin) return foundBin; - } - } - } - return undefined; - }; - return deepSearchBin(app.project.rootItem); - }, - - importFiles: function () { - var filterString = ""; - if (Folder.fs === 'Windows') { - filterString = "All files:*.*"; - } - if (app.project) { - var fileOrFilesToImport = File.openDialog("Choose files to import", // title - filterString, // filter available files? - true); // allow multiple? - if (fileOrFilesToImport) { - // We have an array of File objects; importFiles() takes an array of paths. - var importThese = []; - if (importThese) { - for (var i = 0; i < fileOrFilesToImport.length; i++) { - importThese[i] = fileOrFilesToImport[i].fsName; - } - app.project.importFiles(importThese, - 1, // suppress warnings - app.project.getInsertionBin(), - 0); // import as numbered stills - } - } else { - $._PPP_.updateEventPanel("No files to import."); - } - } - }, - - muteFun: function () { - if (app.project.activeSequence) { - for (var i = 0; i < app.project.activeSequence.audioTracks.numTracks; i++) { - var currentTrack = app.project.activeSequence.audioTracks[i]; - if (Math.random() > 0.5) { - currentTrack.setMute(!(currentTrack.isMuted())); - } - } - } else { - $._PPP_.updateEventPanel("No active sequence."); - } - }, - - disableImportWorkspaceWithProjects: function () { - var prefToModify = 'FE.Prefs.ImportWorkspace'; - var appProperties = app.properties; - - if (appProperties) { - var propertyExists = app.properties.doesPropertyExist(prefToModify); - var propertyIsReadOnly = app.properties.isPropertyReadOnly(prefToModify); - var propertyValue = app.properties.getProperty(prefToModify); - - appProperties.setProperty(prefToModify, false, 1); // optional 3rd param : 0 = non-persistent, 1 = persistent (default) - var safetyCheck = app.properties.getProperty(prefToModify); - if (safetyCheck != propertyValue) { - $._PPP_.updateEventPanel("Changed \'Import Workspaces with Projects\' from " + propertyValue + " to " + safetyCheck + "."); - } - } else { - $._PPP_.updateEventPanel("Properties not found."); - } - }, - - turnOffStartDialog: function () { - var prefToModify = 'MZ.Prefs.ShowQuickstartDialog'; - var appProperties = app.properties; - if (appProperties) { - var propertyExists = app.properties.doesPropertyExist(prefToModify); - var propertyIsReadOnly = app.properties.isPropertyReadOnly(prefToModify); - var originalValue = app.properties.getProperty(prefToModify); - - appProperties.setProperty(prefToModify, false, 1, 1); // optional 4th param : 0 = non-persistent, 1 = persistent (default) - var safetyCheck = app.properties.getProperty(prefToModify); - if (safetyCheck != originalValue) { - $._PPP_.updateEventPanel("Start dialog now OFF. Enjoy!"); - } else { - $._PPP_.updateEventPanel("Start dialog was already OFF."); - } - } else { - $._PPP_.updateEventPanel("Properties not found."); - } - }, - - replaceMedia: function () { - - // Note: This method of changing paths for projectItems is from the time - // before PPro supported full-res AND proxy paths for each projectItem. - // This can still be used, and will change the hi-res projectItem path, but - // if your panel supports proxy workflows, it should rely instead upon - // projectItem.setProxyPath() instead. - - var firstProjectItem = app.project.rootItem.children[0]; - if (firstProjectItem) { - if (firstProjectItem.canChangeMediaPath()) { - - // NEW in 9.0: setScaleToFrameSize() ensures that for all clips created from this footage, - // auto scale to frame size will be ON, regardless of the current user preference. - // This is important for proxy workflows, to avoid mis-scaling upon replacement. - - // Addendum: This setting will be in effect the NEXT time the projectItem is added to a - // sequence; it will not affect or reinterpret clips from this projectItem, already in - // sequences. - - firstProjectItem.setScaleToFrameSize(); - var filterString = ""; - if (Folder.fs === 'Windows') { - filterString = "All files:*.*"; - } - var replacementMedia = File.openDialog("Choose new media file, for " + - firstProjectItem.name, - filterString, // file filter - false); // allow multiple? - - if (replacementMedia) { - var suppressWarnings = true; - firstProjectItem.name = replacementMedia.name + ", formerly known as " + firstProjectItem.name; - firstProjectItem.changeMediaPath(replacementMedia.fsName, suppressWarnings); // new in 12.1 - replacementMedia.close(); - } - } else { - $._PPP_.updateEventPanel("Couldn't change path of " + firstProjectItem.name + "."); - } - } else { - $._PPP_.updateEventPanel("No project items found."); - } - }, - - openProject: function () { - var filterString = ""; - if (Folder.fs === 'Windows') { - filterString = "Premiere Pro project files:*.prproj"; - } - var projToOpen = File.openDialog("Choose project:", - filterString, - false); - if ((projToOpen) && projToOpen.exists) { - app.openDocument(projToOpen.fsName, - 1, // suppress 'Convert Project' dialogs? - 1, // suppress 'Locate Files' dialogs? - 1); // suppress warning dialogs? - projToOpen.close(); - } - }, - - exportFramesForMarkers: function () { - app.enableQE(); - var activeSequence = app.project.activeSequence; - if (activeSequence) { - var markers = activeSequence.markers; - var markerCount = markers.numMarkers; - if (markerCount) { - var firstMarker = markers.getFirstMarker(); - activeSequence.setPlayerPosition(firstMarker.start.ticks); - $._PPP_.exportCurrentFrameAsPNG(); - - var previousMarker = 0; - if (firstMarker) { - for (var i = 0; i < markerCount; i++) { - if (i === 0) { - currentMarker = markers.getNextMarker(firstMarker); - } else { - currentMarker = markers.getNextMarker(previousMarker); - } - if (currentMarker) { - activeSequence.setPlayerPosition(currentMarker.start.ticks); - previousMarker = currentMarker; - $._PPP_.exportCurrentFrameAsPNG(); - } - } - } - } else { - $._PPP_.updateEventPanel("No markers applied to " + activeSequence.name + "."); - } - } else { - $._PPP_.updateEventPanel("No active sequence."); - } - }, - - createSequence: function (name) { - var someID = "xyz123"; - var seqName = prompt('Name of sequence?', '<<>>', 'Sequence Naming Prompt'); - app.project.createNewSequence(seqName, someID); - }, - - createSequenceFromPreset: function (presetPath) { - app.enableQE(); - var seqName = prompt('Name of sequence?', '<<>>', 'Sequence Naming Prompt'); - if (seqName) { - qe.project.newSequence(seqName, presetPath); - } - }, - - transcode: function (outputPresetPath) { - app.encoder.bind('onEncoderJobComplete', $._PPP_.onEncoderJobComplete); - app.encoder.bind('onEncoderJobError', $._PPP_.onEncoderJobError); - app.encoder.bind('onEncoderJobProgress', $._PPP_.onEncoderJobProgress); - app.encoder.bind('onEncoderJobQueued', $._PPP_.onEncoderJobQueued); - app.encoder.bind('onEncoderJobCanceled', $._PPP_.onEncoderJobCanceled); - - var projRoot = app.project.rootItem.children; - - if (projRoot.numItems) { - var firstProjectItem = app.project.rootItem.children[0]; - if (firstProjectItem) { - - app.encoder.launchEncoder(); // This can take a while; let's get the ball rolling. - - var fileOutputPath = Folder.selectDialog("Choose the output directory"); - if (fileOutputPath) { - var outputName = firstProjectItem.name.search('[.]'); - if (outputName == -1) { - outputName = firstProjectItem.name.length; - } - outFileName = firstProjectItem.name.substr(0, outputName); - outFileName = outFileName.replace('/', '-'); - var completeOutputPath = fileOutputPath.fsName + $._PPP_.getSep() + outFileName + '.mxf'; - var removeFromQueue = true; - var rangeToEncode = app.encoder.ENCODE_IN_TO_OUT; - app.encoder.encodeProjectItem(firstProjectItem, - completeOutputPath, - outputPresetPath, - rangeToEncode, - removeFromQueue); - app.encoder.startBatch(); - } - } else { - $._PPP_.updateEventPanel("No project items found."); - } - } else { - $._PPP_.updateEventPanel("Project is empty."); - } - }, - - transcodeExternal: function (outputPresetPath) { - app.encoder.launchEncoder(); - var filterString = ""; - if (Folder.fs === 'Windows') { - filterString = "All files:*.*"; - } - var fileToTranscode = File.openDialog("Choose file to open.", - filterString, - false); - if (fileToTranscode) { - var fileOutputPath = Folder.selectDialog("Choose the output directory"); - if (fileOutputPath) { - - var srcInPoint = 1.0; // encode start time at 1s (optional--if omitted, encode entire file) - var srcOutPoint = 3.0; // encode stop time at 3s (optional--if omitted, encode entire file) - var removeFromQueue = false; - - var result = app.encoder.encodeFile(fileToTranscode.fsName, - fileOutputPath.fsName, - outputPresetPath, - removeFromQueue, - srcInPoint, - srcOutPoint); - } - } - }, - - render: function (outputPresetPath) { - app.enableQE(); - var activeSequence = qe.project.getActiveSequence(); // we use a QE DOM function, to determine the output extension. - if (activeSequence) { - app.encoder.launchEncoder(); // This can take a while; let's get the ball rolling. - - var timeSecs = activeSequence.CTI.secs; // Just for reference, here's how to access the CTI - var timeFrames = activeSequence.CTI.frames; // (Current Time Indicator), for the active sequence. - var timeTicks = activeSequence.CTI.ticks; - var timeString = activeSequence.CTI.timecode; - - var seqInPoint = app.project.activeSequence.getInPoint(); // new in 9.0 - var seqOutPoint = app.project.activeSequence.getOutPoint(); // new in 9.0 - - var seqInPointAsTime = app.project.activeSequence.getInPointAsTime(); // new in 12.0 - var seqOutPointAsTime = app.project.activeSequence.getOutPointAsTime(); // new in 12.0 - - var projPath = new File(app.project.path); - var outputPath = Folder.selectDialog("Choose the output directory"); - - if ((outputPath) && projPath.exists) { - var outPreset = new File(outputPresetPath); - if (outPreset.exists === true) { - var outputFormatExtension = activeSequence.getExportFileExtension(outPreset.fsName); - if (outputFormatExtension) { - var outputFilename = activeSequence.name + '.' + outputFormatExtension; - - var fullPathToFile = outputPath.fsName + - $._PPP_.getSep() + - activeSequence.name + - "." + - outputFormatExtension; - - var outFileTest = new File(fullPathToFile); - - if (outFileTest.exists) { - var destroyExisting = confirm("A file with that name already exists; overwrite?", false, "Are you sure...?"); - if (destroyExisting) { - outFileTest.remove(); - outFileTest.close(); - } - } - - app.encoder.bind('onEncoderJobComplete', $._PPP_.onEncoderJobComplete); - app.encoder.bind('onEncoderJobError', $._PPP_.onEncoderJobError); - app.encoder.bind('onEncoderJobProgress', $._PPP_.onEncoderJobProgress); - app.encoder.bind('onEncoderJobQueued', $._PPP_.onEncoderJobQueued); - app.encoder.bind('onEncoderJobCanceled', $._PPP_.onEncoderJobCanceled); - - - // use these 0 or 1 settings to disable some/all metadata creation. - - app.encoder.setSidecarXMPEnabled(0); - app.encoder.setEmbeddedXMPEnabled(0); - - /* - - For reference, here's how to export from within PPro (blocking further user interaction). - - var seq = app.project.activeSequence; - - if (seq) { - seq.exportAsMediaDirect(fullPathToFile, - outPreset.fsName, - app.encoder.ENCODE_WORKAREA); - - Bonus: Here's how to compute a sequence's duration, in ticks. 254016000000 ticks/second. - var sequenceDuration = app.project.activeSequence.end - app.project.activeSequence.zeroPoint; - } - - */ - - var jobID = app.encoder.encodeSequence(app.project.activeSequence, - fullPathToFile, - outPreset.fsName, - app.encoder.ENCODE_IN_TO_OUT, - 1); // Remove from queue upon successful completion? - $._PPP_.updateEventPanel('jobID = ' + jobID); - outPreset.close(); - } - } else { - $._PPP_.updateEventPanel("Could not find output preset."); - } - } else { - $._PPP_.updateEventPanel("Could not find/create output path."); - } - projPath.close(); - } else { - $._PPP_.updateEventPanel("No active sequence."); - } - }, - - saveProjectCopy: function () { - var sessionCounter = 1; - var originalPath = app.project.path; - var outputPath = Folder.selectDialog("Choose the output directory"); - - if (outputPath) { - var absPath = outputPath.fsName; - var outputName = String(app.project.name); - var array = outputName.split('.', 2); - - outputName = array[0] + sessionCounter + '.' + array[1]; - sessionCounter++; - - var fullOutPath = absPath + $._PPP_.getSep() + outputName; - - app.project.saveAs(fullOutPath); - - for (var a = 0; a < app.projects.numProjects; a++) { - var currentProject = app.projects[a]; - if (currentProject.path === fullOutPath) { - app.openDocument(originalPath); // Why first? So we don't frighten the user by making PPro's window disappear. :) - currentProject.closeDocument(); - } - } - } else { - $._PPP_.updateEventPanel("No output path chosen."); - } - }, - - mungeXMP: function () { - var projectItem = app.project.rootItem.children[0]; // assumes first item is footage. - if (projectItem) { - if (ExternalObject.AdobeXMPScript === undefined) { - ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript'); - } - if (ExternalObject.AdobeXMPScript !== undefined) { // safety-conscious! - - var xmpBlob = projectItem.getXMPMetadata(); - var xmp = new XMPMeta(xmpBlob); - var oldSceneVal = ""; - var oldDMCreatorVal = ""; - - if (xmp.doesPropertyExist(XMPConst.NS_DM, "scene") === true) { - var myScene = xmp.getProperty(XMPConst.NS_DM, "scene"); - oldSceneVal = myScene.value; - } - - if (xmp.doesPropertyExist(XMPConst.NS_DM, "creator") === true) { - var myCreator = xmp.getProperty(XMPConst.NS_DM, "creator"); - oldCreatorVal = myCreator.value; - } - - // Regardless of whether there WAS scene or creator data, set scene and creator data. - - xmp.setProperty(XMPConst.NS_DM, "scene", oldSceneVal + " Added by PProPanel sample!"); - xmp.setProperty(XMPConst.NS_DM, "creator", oldDMCreatorVal + " Added by PProPanel sample!"); - - // That was the NS_DM creator; here's the NS_DC creator. - - var creatorProp = "creator"; - var containsDMCreatorValue = xmp.doesPropertyExist(XMPConst.NS_DC, creatorProp); - var numCreatorValuesPresent = xmp.countArrayItems(XMPConst.NS_DC, creatorProp); - var CreatorsSeparatedBy4PoundSigns = ""; - - if (numCreatorValuesPresent > 0) { - for (var z = 0; z < numCreatorValuesPresent; z++) { - CreatorsSeparatedBy4PoundSigns = CreatorsSeparatedBy4PoundSigns + xmp.getArrayItem(XMPConst.NS_DC, creatorProp, z + 1); - CreatorsSeparatedBy4PoundSigns = CreatorsSeparatedBy4PoundSigns + "####"; - } - $._PPP_.updateEventPanel(CreatorsSeparatedBy4PoundSigns); - - if (confirm("Replace previous?", false, "Replace existing Creator?")) { - xmp.deleteProperty(XMPConst.NS_DC, "creator"); - } - xmp.appendArrayItem(XMPConst.NS_DC, // If no values exist, appendArrayItem will create a value. - creatorProp, - numCreatorValuesPresent + " creator values were already present.", - null, - XMPConst.ARRAY_IS_ORDERED); - - } else { - - xmp.appendArrayItem(XMPConst.NS_DC, - creatorProp, - "PProPanel wrote the first value into NS_DC creator field.", - null, - XMPConst.ARRAY_IS_ORDERED); - } - var xmpAsString = xmp.serialize(); // either way, serialize and write XMP. - projectItem.setXMPMetadata(xmpAsString); - } - } else { - $._PPP_.updateEventPanel("Project item required."); - } - }, - - getProductionByName: function (nameToGet) { - var production; - for (var i = 0; i < productionList.numProductions; i++) { - var currentProduction = productionList[i]; - - if (currentProduction.name == nameToGet) { - production = currentProduction; - } - } - return production; - }, - - pokeAnywhere: function () { - var token = app.anywhere.getAuthenticationToken(); - var productionList = app.anywhere.listProductions(); - var isProductionOpen = app.anywhere.isProductionOpen(); - if (isProductionOpen === true) { - var sessionURL = app.anywhere.getCurrentEditingSessionURL(); - var selectionURL = app.anywhere.getCurrentEditingSessionSelectionURL(); - var activeSequenceURL = app.anywhere.getCurrentEditingSessionActiveSequenceURL(); - - var theOneIAskedFor = $._PPP_.getProductionByName("test"); - - if (theOneIAskedFor) { - var out = theOneIAskedFor.name + ", " + theOneIAskedFor.description; - $._PPP_.updateEventPanel("Found: " + out); // todo: put useful code here. - } - } else { - $._PPP_.updateEventPanel("No Production open."); - } - }, - - dumpOMF: function () { - var activeSequence = app.project.activeSequence; - if (activeSequence) { - var outputPath = Folder.selectDialog("Choose the output directory"); - if (outputPath) { - var absPath = outputPath.fsName; - var outputName = String(activeSequence.name) + '.omf'; - var fullOutPathWithName = absPath + $._PPP_.getSep() + outputName; - - app.project.exportOMF(app.project.activeSequence, // sequence - fullOutPathWithName, // output file path - 'OMFTitle', // OMF title - 48000, // sample rate (48000 or 96000) - 16, // bits per sample (16 or 24) - 1, // audio encapsulated flag (1 : yes or 0 : no) - 0, // audio file format (0 : AIFF or 1 : WAV) - 0, // trim audio files (0 : no or 1 : yes) - 0, // handle frames (if trim is 1, handle frames from 0 to 1000) - 0); // include pan flag (0 : no or 1 : yes) - } - } else { - $._PPP_.updateEventPanel("No active sequence."); - } - }, - - addClipMarkers: function () { - if (app.project.rootItem.children.numItems > 0) { - var projectItem = app.project.rootItem.children[0]; // assumes first item is footage. - if (projectItem) { - if (projectItem.type == ProjectItemType.CLIP || projectItem.type == ProjectItemType.FILE) { - - markers = projectItem.getMarkers(); - - if (markers) { - var num_markers = markers.numMarkers; - var new_marker = markers.createMarker(12.345); - var guid = new_marker.guid; // new in 11.1 - - new_marker.name = 'Marker created by PProPanel.'; - new_marker.comments = 'Here are some comments, inserted by PProPanel.'; - new_marker.end = 15.6789; - - //default marker type == comment. To change marker type, call one of these: - - // new_marker.setTypeAsChapter(); - // new_marker.setTypeAsWebLink(); - // new_marker.setTypeAsSegmentation(); - // new_marker.setTypeAsComment(); - } - } else { - $._PPP_.updateEventPanel("Can only add markers to footage items."); - } - } else { - $._PPP_.updateEventPanel("Could not find first projectItem."); - } - } else { - $._PPP_.updateEventPanel("Project is empty."); - } - }, - - modifyProjectMetadata: function () { - var kPProPrivateProjectMetadataURI = "http://ns.adobe.com/premierePrivateProjectMetaData/1.0/"; - - var namefield = "Column.Intrinsic.Name"; - var tapename = "Column.Intrinsic.TapeName"; - var desc = "Column.PropertyText.Description"; - var logNote = "Column.Intrinsic.LogNote"; - var newField = "ExampleFieldName"; - - if (app.isDocumentOpen()) { - var projectItem = app.project.rootItem.children[0]; // just grabs first projectItem. - if (projectItem) { - if (ExternalObject.AdobeXMPScript === undefined) { - ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript'); - } - if (ExternalObject.AdobeXMPScript !== undefined) { // safety-conscious! - var projectMetadata = projectItem.getProjectMetadata(); - var successfullyAdded = app.project.addPropertyToProjectMetadataSchema(newField, "ExampleFieldLabel", 2); - - var xmp = new XMPMeta(projectMetadata); - var obj = xmp.dumpObject(); - - // var aliases = xmp.dumpAliases(); - - var namespaces = XMPMeta.dumpNamespaces(); - var found_name = xmp.doesPropertyExist(kPProPrivateProjectMetadataURI, namefield); - var found_tapename = xmp.doesPropertyExist(kPProPrivateProjectMetadataURI, tapename); - var found_desc = xmp.doesPropertyExist(kPProPrivateProjectMetadataURI, desc); - var found_custom = xmp.doesPropertyExist(kPProPrivateProjectMetadataURI, newField); - var foundLogNote = xmp.doesPropertyExist(kPProPrivateProjectMetadataURI, logNote); - var oldLogValue = ""; - var appendThis = "This log note inserted by PProPanel."; - var appendTextWasActuallyNew = false; - - if (foundLogNote) { - var oldLogNote = xmp.getProperty(kPProPrivateProjectMetadataURI, logNote); - if (oldLogNote) { - oldLogValue = oldLogNote.value; - } - } - - xmp.setProperty(kPProPrivateProjectMetadataURI, tapename, "***TAPENAME***"); - xmp.setProperty(kPProPrivateProjectMetadataURI, desc, "***DESCRIPTION***"); - xmp.setProperty(kPProPrivateProjectMetadataURI, namefield, "***NEWNAME***"); - xmp.setProperty(kPProPrivateProjectMetadataURI, newField, "PProPanel set this, using addPropertyToProjectMetadataSchema()."); - - - var array = []; - array[0] = tapename; - array[1] = desc; - array[2] = namefield; - array[3] = newField; - - var concatenatedLogNotes = ""; - - if (oldLogValue != appendThis) { // if that value is not exactly what we were going to add - if (oldLogValue.length > 0) { // if we have a valid value - concatenatedLogNotes += "Previous log notes: " + oldLogValue + " |||| "; - } - concatenatedLogNotes += appendThis; - xmp.setProperty(kPProPrivateProjectMetadataURI, logNote, concatenatedLogNotes); - array[4] = logNote; - } - - var str = xmp.serialize(); - projectItem.setProjectMetadata(str, array); - - // test: is it in there? - - var newblob = projectItem.getProjectMetadata(); - var newXMP = new XMPMeta(newblob); - var foundYet = newXMP.doesPropertyExist(kPProPrivateProjectMetadataURI, newField); - - if (foundYet) { - $._PPP_.updateEventPanel("PProPanel successfully added a field to the project metadata schema, and set a value for it."); - } - } - } else { - $._PPP_.updateEventPanel("No project items found."); - } - } - }, - - updatePAR: function () { - var item = app.project.rootItem.children[0]; - if (item) { - if ((item.type == ProjectItemType.FILE) || (item.type == ProjectItemType.CLIP)) { - // If there is an item, and it's either a clip or file... - item.setOverridePixelAspectRatio(185, 100); // anamorphic is BACK! ;) - } else { - $._PPP_.updateEventPanel('You cannot override the PAR of bins or sequences.'); - } - } else { - $._PPP_.updateEventPanel("No project items found."); - } - }, - - getnumAEProjectItems: function () { - var bt = new BridgeTalk(); - bt.target = 'aftereffects'; - bt.body = //'$._PPP_.updateEventPanel("Items in AE project: " + app.project.rootFolder.numItems);app.quit();'; - 'alert("Items in AE project: " + app.project.rootFolder.numItems);app.quit();'; - bt.send(); - }, - - updateEventPanel: function (message) { - app.setSDKEventMessage(message, 'info'); - //app.setSDKEventMessage('Here is some information.', 'info'); - //app.setSDKEventMessage('Here is a warning.', 'warning'); - //app.setSDKEventMessage('Here is an error.', 'error'); // Very annoying; use sparingly. - }, - - walkAllBinsForFootage: function (parentItem, outPath) { - for (var j = 0; j < parentItem.children.numItems; j++) { - var currentChild = parentItem.children[j]; - if (currentChild) { - if (currentChild.type == ProjectItemType.BIN) { - $._PPP_.walkAllBinsForFootage(currentChild, outPath); // warning; recursion! - } else { - $._PPP_.dumpProjectItemXMP(currentChild, outPath); - } - } - } - }, - - searchBinForProjItemByName: function (i, containingBin, nameToFind) { - for (var j = i; j < containingBin.children.numItems; j++) { - var currentChild = containingBin.children[j]; - if (currentChild) { - if (currentChild.type == ProjectItemType.BIN) { - return $._PPP_.searchBinForProjItemByName(j, currentChild, nameToFind); // warning; recursion! - } else { - if (currentChild.name == nameToFind) { - return currentChild; - } else { - currentChild = currentItem.children[j + 1]; - if (currentChild) { - return $._PPP_.searchBinForProjItemByName(0, currentChild, nameToFind); - } - } - } - } - } - }, - - dumpProjectItemXMP: function (projectItem, outPath) { - var xmpBlob = projectItem.getXMPMetadata(); - var outFileName = projectItem.name + '.xmp'; - var completeOutputPath = outPath + $._PPP_.getSep() + outFileName; - var outFile = new File(completeOutputPath); - - var isThisASequence = projectItem.isSequence(); - - if (outFile) { - outFile.encoding = "UTF8"; - outFile.open("w", "TEXT", "????"); - outFile.write(xmpBlob.toString()); - outFile.close(); - } - }, - - addSubClip: function () { - var startTime = new Time; - startTime.seconds = 0.0; - var endTime = new Time; - endTime.seconds = 3.21; - var hasHardBoundaries = 0; - var sessionCounter = 1; - var takeVideo = 1; // optional, defaults to 1 - var takeAudio = 1; // optional, defaults to 1 - var projectItem = app.project.rootItem.children[0]; // just grabs the first item - if (projectItem) { - if ((projectItem.type == ProjectItemType.CLIP) || (projectItem.type == ProjectItemType.FILE)) { - var newSubClipName = prompt('Name of subclip?', projectItem.name + '_' + sessionCounter, 'Name your subclip'); - - var newSubClip = projectItem.createSubClip(newSubClipName, - startTime, - endTime, - hasHardBoundaries, - takeVideo, - takeAudio); - - if (newSubClip) { - newSubClip.setStartTime(12.345); - } - } else { - $._PPP_.updateEventPanel("Could not sub-clip " + projectItem.name + "."); - } - } else { - $._PPP_.updateEventPanel("No project item found."); - } - }, - - dumpXMPFromAllProjectItems: function () { - var numItemsInRoot = app.project.rootItem.children.numItems; - if (numItemsInRoot > 0) { - var outPath = Folder.selectDialog("Choose the output directory"); - if (outPath) { - for (var i = 0; i < numItemsInRoot; i++) { - var currentItem = app.project.rootItem.children[i]; - if (currentItem) { - if (currentItem.type == ProjectItemType.BIN) { - $._PPP_.walkAllBinsForFootage(currentItem, outPath.fsName); - } else { - $._PPP_.dumpProjectItemXMP(currentItem, outPath.fsName); - } - } - } - } - } else { - $._PPP_.updateEventPanel("No project items found."); - } - }, - - exportAAF: function () { - var sessionCounter = 1; - if (app.project.activeSequence) { - var outputPath = Folder.selectDialog("Choose the output directory"); - if (outputPath) { - var absPath = outputPath.fsName; - var outputName = String(app.project.name); - var array = outputName.split('.', 2); - outputName = array[0] + sessionCounter + '.' + array[1]; - - sessionCounter++; - var fullOutPath = absPath + $._PPP_.getSep() + outputName + '.aaf'; - //var optionalPathToOutputPreset = null; New in 11.0.0, you can specify an output preset. - - app.project.exportAAF(app.project.activeSequence, // which sequence - fullOutPath, // output path - 1, // mix down video? - 0, // explode to mono? - 96000, // sample rate - 16, // bits per sample - 0, // embed audio? - 0, // audio file format? 0 = aiff, 1 = wav - 0, // trim sources? - 0 - /*, // number of 'handle' frames - optionalPathToOutputPreset*/ - ); // optional; .epr file to use - } else { - $._PPP_.updateEventPanel("Couldn't create AAF output."); - } - } else { - $._PPP_.updateEventPanel("No active sequence."); - } - }, - - setScratchDisk: function () { - var scratchPath = Folder.selectDialog("Choose new scratch disk directory"); - if ((scratchPath) && scratchPath.exists) { - app.setScratchDiskPath(scratchPath.fsName, ScratchDiskType.FirstAutoSaveFolder); // see ScratchDiskType object, in ESTK. - } - }, - - getProjectProxySetting: function () { - var returnVal = ""; - if (app.project) { - var returnVal = "No sequence detected in " + app.project.name + "."; - if (app.getEnableProxies()) { - returnVal = 'true'; - } else { - returnVal = 'false'; - } - } else { - returnVal = "No project available."; - } - return returnVal; - }, - - toggleProxyState: function () { - var update = "Proxies for " + app.project.name + " turned "; - if (app.getEnableProxies()) { - app.setEnableProxies(0); - update = update + "OFF."; - app.setSDKEventMessage(update, 'info'); - } else { - app.setEnableProxies(1); - update = update + "ON."; - app.setSDKEventMessage(update, 'info'); - } - }, - - setProxiesON: function () { - var firstProjectItem = app.project.rootItem.children[0]; - if (firstProjectItem) { - if (firstProjectItem.canProxy()) { - var shouldAttachProxy = true; - if (firstProjectItem.hasProxy()) { - shouldAttachProxy = confirm(firstProjectItem.name + " already has an assigned proxy. Re-assign anyway?", false, "Are you sure...?"); - } - if (shouldAttachProxy) { - var filterString = ""; - if (Folder.fs === 'Windows') { - filterString = "All files:*.*"; - } - var proxyPath = File.openDialog("Choose proxy for " + firstProjectItem.name + ":", - filterString, - false); - if (proxyPath.exists) { - firstProjectItem.attachProxy(proxyPath.fsName, 0); - } else { - $._PPP_.updateEventPanel("Could not attach proxy from " + proxyPath + "."); - } - } - } else { - $._PPP_.updateEventPanel("Cannot attach a proxy to " + firstProjectItem.name + "."); - } - } else { - $._PPP_.updateEventPanel("No project item available."); - } - }, - - clearCache: function () { - app.enableQE(); - MediaType = {}; - - // Magical constants from Premiere Pro's internal automation. - - MediaType.VIDEO = "228CDA18-3625-4d2d-951E-348879E4ED93"; - MediaType.AUDIO = "80B8E3D5-6DCA-4195-AEFB-CB5F407AB009"; - MediaType.ANY = "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"; - qe.project.deletePreviewFiles(MediaType.ANY); - $._PPP_.updateEventPanel("All video and audio preview files deleted."); - }, - - randomizeSequenceSelection: function () { - var sequence = app.project.activeSequence; - - if (sequence) { - var trackGroups = [sequence.audioTracks, sequence.videoTracks]; - var trackGroupNames = ["audioTracks", "videoTracks"]; - var updateUI = true; - var before; - - for (var gi = 0; gi < 2; gi++) { - $._PPP_.updateEventPanel(trackGroupNames[gi]); - group = trackGroups[gi]; - for (var ti = 0; ti < group.numTracks; ti++) { - var track = group[ti]; - var clips = track.clips; - var transitions = track.transitions; - var beforeSelected; - var afterSelected; - - $._PPP_.updateEventPanel("track : " + ti + " clip count: " + clips.numTracks + " transition count: " + transitions.numTracks); - - for (var ci = 0; ci < clips.numTracks; ci++) { - var clip = clips[ci]; - name = (clip.projectItem === undefined ? "" : clip.projectItem.name); - before = clip.isSelected(); - - // randomly select clips - clip.setSelected((Math.random() > 0.5), updateUI); - - if (clip.isAdjustmentLayer()) { // new in 13.0 - $._PPP_.updateEventPanel("Clip named \"" + clip.name + "\" is an adjustment layer."); - } - - // Note; there's no good place to exercise this code yet, but - // I wanted to provide example usage. - - var allClipsInThisSequenceFromSameSource = clip.getLinkedItems(); - - if (allClipsInThisSequenceFromSameSource) { - $._PPP_.updateEventPanel("Found " + allClipsInThisSequenceFromSameSource.numItems + " clips from " + clip.projectItem.name + ", in this sequence."); - } - beforeSelected = before ? "Y" : "N"; - afterSelected = clip.selected ? "Y" : "N"; - $._PPP_.updateEventPanel("clip : " + ci + " " + name + " " + beforeSelected + " -> " + afterSelected); - } - - for (var tni = 0; tni < transitions.numTracks; ++tni) { - var transition = transitions[tni]; - before = transition.isSelected(); - - // randomly select transitions - transition.setSelected((Math.random() > 0.5), updateUI); - - beforeSelected = before ? "Y" : "N"; - afterSelected = transition.selected ? "Y" : "N"; - - $._PPP_.updateEventPanel('transition: ' + tni + " " + beforeSelected + " -> " + afterSelected); - } - } - } - } else { - $._PPP_.updateEventPanel("no active sequence."); - } - }, - - // Define a couple of callback functions, for AME to use during render. - - onEncoderJobComplete: function (jobID, outputFilePath) { - var eoName; - - if (Folder.fs == 'Macintosh') { - eoName = "PlugPlugExternalObject"; - } else { - eoName = "PlugPlugExternalObject.dll"; - } - - var suffixAddedByPPro = '_1'; // You should really test for any suffix. - var withoutExtension = outputFilePath.slice(0, -4); // trusting 3 char extension - var lastIndex = outputFilePath.lastIndexOf("."); - var extension = outputFilePath.substr(lastIndex + 1); - - if (outputFilePath.indexOf(suffixAddedByPPro)) { - $._PPP_.updateEventPanel(" Output filename was changed: the output preset name may have been added, or there may have been an existing file with that name. This would be a good place to deal with such occurrences."); - } - - var mylib = new ExternalObject('lib:' + eoName); - var eventObj = new CSXSEvent(); - - eventObj.type = "com.adobe.csxs.events.PProPanelRenderEvent"; - eventObj.data = "Rendered Job " + jobID + ", to " + outputFilePath + "."; - - eventObj.dispatch(); - }, - - onEncoderJobError: function (jobID, errorMessage) { - var eoName; - - if (Folder.fs === 'Macintosh') { - eoName = "PlugPlugExternalObject"; - } else { - eoName = "PlugPlugExternalObject.dll"; - } - - var mylib = new ExternalObject('lib:' + eoName); - var eventObj = new CSXSEvent(); - - eventObj.type = "com.adobe.csxs.events.PProPanelRenderEvent"; - eventObj.data = "Job " + jobID + " failed, due to " + errorMessage + "."; - eventObj.dispatch(); - }, - - onEncoderJobProgress: function (jobID, progress) { - $._PPP_.updateEventPanel('onEncoderJobProgress called. jobID = ' + jobID + '. progress = ' + progress + '.'); - }, - - onEncoderJobQueued: function (jobID) { - app.encoder.startBatch(); - }, - - onEncoderJobCanceled: function (jobID) { - $._PPP_.updateEventPanel('OnEncoderJobCanceled called. jobID = ' + jobID + '.'); - }, - - onPlayWithKeyframes: function () { - var seq = app.project.activeSequence; - if (seq) { - var firstVideoTrack = seq.videoTracks[0]; - if (firstVideoTrack) { - var firstClip = firstVideoTrack.clips[0]; - if (firstClip) { - var clipComponents = firstClip.components; - if (clipComponents) { - for (var i = 0; i < clipComponents.numItems; ++i) { - $._PPP_.updateEventPanel('component ' + i + ' = ' + clipComponents[i].matchName + ' : ' + clipComponents[i].displayName); - } - if (clipComponents.numItems > 2) { - - // 0 = clip - // 1 = Opacity - // N effects, then... - // Shape layer (new in 12.0) - - var blur = clipComponents[2]; // Assume Gaussian Blur is the first effect applied to the clip. - if (blur) { - var blurProps = blur.properties; - if (blurProps) { - for (var j = 0; j < blurProps.numItems; ++j) { - $._PPP_.updateEventPanel('param ' + j + ' = ' + blurProps[j].displayName); - } - var blurriness = blurProps[0]; - if (blurriness) { - if (!blurriness.isTimeVarying()) { - blurriness.setTimeVarying(true); - } - for (var k = 0; k < 20; ++k) { - updateUI = (k == 9); // Decide how often to update PPro's UI - blurriness.addKey(k); - var blurVal = Math.sin(3.14159 * i / 5) * 20 + 25; - blurriness.setValueAtKey(k, blurVal, updateUI); - } - } - var repeatEdgePixels = blurProps[2]; - if (repeatEdgePixels) { - if (!repeatEdgePixels.getValue()) { - updateUI = true; - repeatEdgePixels.setValue(true, updateUI); - } - } - // look for keyframe nearest to 4s with 1/10 second tolerance - var keyFrameTime = blurriness.findNearestKey(4.0, 0.1); - if (keyFrameTime !== undefined) { - $._PPP_.updateEventPanel('Found keyframe = ' + keyFrameTime.seconds); - } else { - $._PPP_.updateEventPanel('Keyframe not found.'); - } - - // scan keyframes, forward - - keyFrameTime = blurriness.findNearestKey(0.0, 0.1); - var lastKeyFrameTime = keyFrameTime; - while (keyFrameTime !== undefined) { - $._PPP_.updateEventPanel('keyframe @ ' + keyFrameTime.seconds); - lastKeyFrameTime = keyFrameTime; - keyFrameTime = blurriness.findNextKey(keyFrameTime); - } - - // scan keyframes, backward - keyFrameTime = lastKeyFrameTime; - while (keyFrameTime !== undefined) { - $._PPP_.updateEventPanel('keyframe @ ' + keyFrameTime.seconds); - lastKeyFrameTime = keyFrameTime; - keyFrameTime = blurriness.findPreviousKey(keyFrameTime); - } - - // get all keyframes - - var blurKeyframesArray = blurriness.getKeys(); - if (blurKeyframesArray) { - $._PPP_.updateEventPanel(blurKeyframesArray.length + ' keyframes found'); - } - - // remove keyframe at 19s - blurriness.removeKey(19); - - // remove keyframes in range from 0s to 5s - var shouldUpdateUI = true; - blurriness.removeKeyRange(0, 5, shouldUpdateUI); - } - - } else { - $._PPP_.updateEventPanel("Please apply the Gaussian Blur effect to the first clip in the first video track of the active sequence."); - } - } - } - } - } - } else { - $._PPP_.updateEventPanel("no active sequence."); - } - }, - - extractFileNameFromPath: function (fullPath) { - var lastDot = fullPath.lastIndexOf("."); - var lastSep = fullPath.lastIndexOf("/"); - - if (lastDot > -1) { - return fullPath.substr((lastSep + 1), (fullPath.length - (lastDot + 1))); - } else { - return fullPath; - } - }, - - onProxyTranscodeJobComplete: function (jobID, outputFilePath) { - var suffixAddedByPPro = '_1'; // You should really test for any suffix. - var withoutExtension = outputFilePath.slice(0, -4); // trusting 3 char extension - var lastIndex = outputFilePath.lastIndexOf("."); - var extension = outputFilePath.substr(lastIndex + 1); - - var wrapper = []; - wrapper[0] = outputFilePath; - - var nameToFind = 'Proxies generated by PProPanel'; - var targetBin = $._PPP_.getPPPInsertionBin(); - if (targetBin) { - app.project.importFiles(wrapper); - } - }, - - onProxyTranscodeJobError: function (jobID, errorMessage) { - $._PPP_.updateEventPanel(errorMessage); - }, - - onProxyTranscodeJobQueued: function (jobID) { - app.encoder.startBatch(); - }, - - ingestFiles: function (outputPresetPath) { - app.encoder.bind('onEncoderJobComplete', $._PPP_.onProxyTranscodeJobComplete); - app.encoder.bind('onEncoderJobError', $._PPP_.onProxyTranscodeJobError); - app.encoder.bind('onEncoderJobQueued', $._PPP_.onProxyTranscodeJobQueued); - app.encoder.bind('onEncoderJobCanceled', $._PPP_.onEncoderJobCanceled); - - if (app.project) { - var filterString = ""; - if (Folder.fs === 'Windows') { - filterString = "All files:*.*"; - } - var fileOrFilesToImport = File.openDialog("Choose full resolution files to import", // title - filterString, // filter available files? - true); // allow multiple? - if (fileOrFilesToImport) { - var nameToFind = 'Proxies generated by PProPanel'; - var targetBin = $._PPP_.searchForBinWithName(nameToFind); - if (targetBin === 0) { - // If panel can't find the target bin, it creates it. - app.project.rootItem.createBin(nameToFind); - targetBin = $._PPP_.searchForBinWithName(nameToFind); - } - if (targetBin) { - targetBin.select(); - var importThese = []; // We have an array of File objects; importFiles() takes an array of paths. - if (importThese) { - for (var i = 0; i < fileOrFilesToImport.length; i++) { - importThese[i] = fileOrFilesToImport[i].fsName; - var justFileName = extractFileNameFromPath(importThese[i]); - var suffix = '_PROXY.mp4'; - var containingPath = fileOrFilesToImport[i].parent.fsName; - var completeProxyPath = containingPath + $._PPP_.getSep() + justFileName + suffix; - - var jobID = app.encoder.encodeFile(fileOrFilesToImport[i].fsName, - completeProxyPath, - outputPresetPath, - 0); - } - - app.project.importFiles(importThese, - 1, // suppress warnings - targetBin, - 0); // import as numbered stills - } - } else { - $._PPP_.updateEventPanel("Could not find or create target bin."); - } - } else { - $._PPP_.updateEventPanel("No files to import."); - } - } else { - $._PPP_.updateEventPanel("No project found."); - } - }, - - insertOrAppend: function () { - var seq = app.project.activeSequence; - if (seq) { - var first = app.project.rootItem.children[0]; - if (first) { - var numVTracks = seq.videoTracks.numTracks; - var targetVTrack = seq.videoTracks[(numVTracks - 1)]; - if (targetVTrack) { - // If there are already clips in this track, - // append this one to the end. Otherwise, - // insert at start time. - - if (targetVTrack.clips.numItems > 0) { - var lastClip = targetVTrack.clips[(targetVTrack.clips.numItems - 1)]; - if (lastClip) { - targetVTrack.insertClip(first, lastClip.end.seconds); - } - } else { - targetVTrack.insertClip(first, '00;00;00;00'); - } - } else { - $._PPP_.updateEventPanel("Could not find first video track."); - } - } else { - $._PPP_.updateEventPanel("Couldn't locate first projectItem."); - } - } else { - $._PPP_.updateEventPanel("no active sequence."); - } - }, - - overWrite: function () { - var seq = app.project.activeSequence; - if (seq) { - var first = app.project.rootItem.children[0]; - if (first) { - var vTrack1 = seq.videoTracks[0]; - if (vTrack1) { - var now = seq.getPlayerPosition(); - vTrack1.overwriteClip(first, now.seconds); - } else { - $._PPP_.updateEventPanel("Could not find first video track."); - } - } else { - $._PPP_.updateEventPanel("Couldn't locate first projectItem."); - } - } else { - $._PPP_.updateEventPanel("no active sequence."); - } - }, - - closeFrontSourceClip: function () { - app.sourceMonitor.closeClip(); - }, - - closeAllClipsInSourceMonitor: function () { - app.sourceMonitor.closeAllClips(); - }, - - changeLabel: function () { - var first = app.project.rootItem.children[0]; - if (first) { - var currentLabel = first.getColorLabel(); - var newLabel = currentLabel + 1; // 4 = Cerulean. 0 = Violet, 15 = Yellow. - if (newLabel > 15) { - newLabel = newLabel - 16; - } - app.setSDKEventMessage("Previous Label color = " + currentLabel + ".", 'info'); - first.setColorLabel(newLabel); - app.setSDKEventMessage("New Label color = " + newLabel + ".", 'info'); - } else { - $._PPP_.updateEventPanel("Couldn't locate first projectItem."); - } - }, - - getPPPInsertionBin: function () { - var nameToFind = "Here's where PProPanel puts things."; - - var targetBin = $._PPP_.searchForBinWithName(nameToFind); - - if (targetBin === undefined) { - // If panel can't find the target bin, it creates it. - app.project.rootItem.createBin(nameToFind); - targetBin = $._PPP_.searchForBinWithName(nameToFind); - } - if (targetBin) { - targetBin.select(); - return targetBin; - } - }, - - importComps: function () { - var targetBin = $._PPP_.getPPPInsertionBin(); - if (targetBin) { - var filterString = ""; - if (Folder.fs === 'Windows') { - filterString = "All files:*.*"; - } - compNamesToImport = []; - - var aepToImport = File.openDialog("Choose After Effects project", // title - filterString, // filter available files? - false); // allow multiple? - if (aepToImport) { - var importAll = confirm("Import all compositions in project?", false, "Import all?"); - if (importAll) { - var result = app.project.importAllAEComps(aepToImport.fsName, targetBin); - } else { - var compName = prompt('Name of composition to import?', - '', - 'Which Comp to import'); - if (compName) { - compNamesToImport[0] = compName; - var importAECompResult = app.project.importAEComps(aepToImport.fsName, compNamesToImport, targetBin); - } else { - $._PPP_.updateEventPanel("Could not find Composition."); - } - } - } else { - $._PPP_.updateEventPanel("Could not open project."); - } - } else { - $._PPP_.updateEventPanel("Could not find or create target bin."); - } - }, - - consolidateProject: function () { - var pmo = app.projectManager.options; - - if (app.project.sequences.length) { - if (pmo) { - var filterString = ""; - if (Folder.fs === 'Windows') { - filterString = "Output Presets:*.epr"; - } - - var outFolder = Folder.selectDialog("Choose output directory."); - if (outFolder) { - - var presetPath = ""; - var useSpecificPreset = confirm("Would you like to select an output preset?", false, "Are you sure...?"); - if (useSpecificPreset) { - var useThisEPR = File.openDialog("Choose output preset (.epr file)", // title - filterString, // filter available files? - false); // allow multiple? - - if (useThisEPR) { - pmo.clipTranscoderOption = pmo.CLIP_TRANSCODE_MATCH_PRESET; - pmo.encoderPresetFilePath = useThisEPR.fsName; - } - } else { - pmo.clipTranscoderOption = pmo.CLIP_TRANSCODE_MATCH_SEQUENCE; - } - - var processAllSequences = confirm("Process all sequences? No = just the first sequence found.", true, "Process all?"); - - if (processAllSequences) { - pmo.includeAllSequences = true; - } else { - pmo.includeAllSequences = false; - pmo.affectedSequences = [app.project.sequences[0]]; - } - - pmo.clipTransferOption = pmo.CLIP_TRANSFER_TRANSCODE; - pmo.convertAECompsToClips = false; - pmo.convertSyntheticsToClips = false; - pmo.copyToPreventAlphaLoss = false; - pmo.destinationPath = outFolder.fsName; - pmo.excludeUnused = false; - pmo.handleFrameCount = 0; - pmo.includeConformedAudio = true; - pmo.includePreviews = true; - pmo.renameMedia = false; - - var result = app.projectManager.process(app.project); - var errorList = app.projectManager.errors; - - if (errorList.length) { - for (var k = 0; k < errorList.length; k++) { - $._PPP_.updateEventPanel(errorList[k][1]); - } - } else { - $._PPP_.updateEventPanel(app.project.name + " successfully processed to " + outFolder.fsName + "."); - } - return result; - } - } - - - } - if (pmo) { - var filterString = ""; - if (Folder.fs === 'Windows') { - filterString = "Output Presets:*.epr"; - } - - var outFolder = Folder.selectDialog("Choose output directory."); - if (outFolder) { - - var presetPath = ""; - var useSpecificPreset = confirm("Would you like to select an output preset?", false, "Are you sure...?"); - if (useSpecificPreset) { - var useThisEPR = File.openDialog("Choose output preset (.epr file)", // title - filterString, // filter available files? - false); // allow multiple? - - if (useThisEPR) { - pmo.clipTranscoderOption = pmo.CLIP_TRANSCODE_MATCH_PRESET; - pmo.encoderPresetFilePath = useThisEPR.fsName; - } - } else { - pmo.clipTranscoderOption = pmo.CLIP_TRANSCODE_MATCH_SEQUENCE; - } - - var processAllSequences = confirm("Process all sequences? No = just the first sequence found.", true, "Process all?"); - - if (processAllSequences) { - pmo.includeAllSequences = true; - } else { - pmo.includeAllSequences = false; - pmo.affectedSequences = [app.project.sequences[0]]; - } - - pmo.clipTransferOption = pmo.CLIP_TRANSFER_TRANSCODE; - pmo.convertAECompsToClips = false; - pmo.convertSyntheticsToClips = false; - pmo.copyToPreventAlphaLoss = false; - pmo.destinationPath = outFolder.fsName; - pmo.excludeUnused = false; - pmo.handleFrameCount = 0; - pmo.includeConformedAudio = true; - pmo.includePreviews = true; - pmo.renameMedia = false; - - var result = app.projectManager.process(app.project); - var errorList = app.projectManager.errors; - - if (errorList.length) { - for (var k = 0; k < errorList.length; k++) { - $._PPP_.updateEventPanel(errorList[k][1]); - } - } else { - $._PPP_.updateEventPanel(app.project.name + " successfully processed to " + outFolder.fsName + "."); - } - return result; - } - } - }, - - importMoGRT: function () { - var activeSeq = app.project.activeSequence; - if (activeSeq) { - var filterString = ""; - if (Folder.fs === 'Windows') { - filterString = "Motion Graphics Templates:*.mogrt"; - } - var mogrtToImport = File.openDialog("Choose MoGRT", // title - filterString, // filter available files? - false); // allow multiple? - if (mogrtToImport) { - var targetTime = activeSeq.getPlayerPosition(); - var vidTrackOffset = 0; - var audTrackOffset = 0; - var newTrackItem = activeSeq.importMGT(mogrtToImport.fsName, - targetTime.ticks, - vidTrackOffset, - audTrackOffset); - if (newTrackItem) { - var moComp = newTrackItem.getMGTComponent(); - if (moComp) { - var params = moComp.properties; - for (var z = 0; z < params.numItems; z++) { - var thisParam = params[0]; - } - var srcTextParam = params.getParamForDisplayName("Main Title"); - if (srcTextParam) { - var val = srcTextParam.getValue(); - srcTextParam.setValue("New value set by PProPanel!"); - } - } - } - } else { - app.setSDKEventMessage('Unable to import ' + mogrtToImport.fsName + '.', 'error'); - } - } else { - app.setSDKEventMessage('No active sequence.'); - } - }, - - reportCurrentProjectSelection: function () { - var viewIDs = app.getProjectViewIDs(); // sample code optimized for a single open project - viewSelection = app.getProjectViewSelection(viewIDs[0]); - $._PPP_.projectPanelSelectionChanged(viewSelection, viewIDs[0]); - }, - - randomizeProjectSelection: function () { - var viewIDs = app.getProjectViewIDs(); - var firstProject = app.getProjectFromViewID(viewIDs[0]); - var arrayOfRandomProjectItems = []; - - for (var b = 0; b < app.project.rootItem.children.numItems; b++) { - var currentProjectItem = app.project.rootItem.children[b]; - if (Math.random() > 0.5) { - arrayOfRandomProjectItems.push(currentProjectItem); - } - } - if (arrayOfRandomProjectItems.length > 0) { - app.setProjectViewSelection(arrayOfRandomProjectItems, viewIDs[0]); - } - }, - - setAllProjectItemsOnline: function (startingBin) { - for (var k = 0; k < startingBin.children.numItems; k++) { - var currentChild = startingBin.children[k]; - if (currentChild) { - if (currentChild.type === ProjectItemType.BIN) { - $._PPP_.setAllProjectItemsOnline(currentChild); // warning; recursion! - } else if (currentChild.isOffline()) { - currentChild.changeMediaPath(currentChild.getMediaPath(), true); - if (currentChild.isOffline()) { - $._PPP_.updateEventPanel("Failed to bring \'" + currentChild.name + "\' online."); - } else { - $._PPP_.updateEventPanel("\'" + currentChild.name + "\' is once again online."); - } - } - } - } - }, - - setAllOnline: function () { - var startingBin = app.project.rootItem; - $._PPP_.setAllProjectItemsOnline(startingBin); - }, - - setOffline: function () { - var viewIDs = app.getProjectViewIDs(); - for (var a = 0; a < app.projects.numProjects; a++) { - var currentProject = app.getProjectFromViewID(viewIDs[a]); - if (currentProject) { - if (currentProject.documentID === app.project.documentID) { // We're in the right project! - var selectedItems = app.getProjectViewSelection(viewIDs[a]); - for (var b = 0; b < selectedItems.length; b++) { - var currentItem = selectedItems[b]; - if (currentItem) { - if ((!currentItem.isSequence()) && (currentItem.type !== ProjectItemType.BIN)) { // For every selected item which isn't a bin or sequence... - if (currentItem.isOffline()) { - $._PPP_.updateEventPanel("\'" + currentItem.name + "\'was already offline."); - } else { - var result = currentItem.setOffline(); - $._PPP_.updateEventPanel("\'" + currentItem.name + "\' is now offline."); - } - } - } - } - } - } - } - }, - - updateFrameRate: function () { - var item = app.project.rootItem.children[0]; - if (item) { - if ((item.type == ProjectItemType.FILE) || (item.type == ProjectItemType.CLIP)) { - // If there is an item, and it's either a clip or file... - item.setOverrideFrameRate(23.976); - } else { - $._PPP_.updateEventPanel('You cannot override the frame rate of bins or sequences.'); - } - } else { - $._PPP_.updateEventPanel("No project items found."); - } - }, - - onItemAddedToProject: function (whichProject, addedProjectItem) { - var msg = addedProjectItem.name + " was added to " + whichProject + "." - $._PPP_.updateEventPanel(msg); - }, - - registerItemAddedFxn: function () { - app.onItemAddedToProjectSuccess = $._PPP_.onItemAddedToProject; - }, - - myOnProjectChanged: function (documentID) { - var msg = 'Project with ID ' + documentID + ' Changed.'; - // Commented out, as this happens a LOT. - // $._PPP_.updateEventPanel(msg); - }, - - registerProjectChangedFxn: function () { - app.bind('onProjectChanged', $._PPP_.myOnProjectChanged); - }, - - confirmPProHostVersion: function () { - var version = parseFloat(app.version); - if (version < 12.1) { - $._PPP_.updateEventPanel("Note: PProPanel relies on features added in 12.1, but is currently running in " + version + "."); - } - }, - - changeMarkerColors: function () { - if (app.project.rootItem.children.numItems > 0) { - var projectItem = app.project.rootItem.children[0]; // assumes first item is footage. - if (projectItem) { - if (projectItem.type == ProjectItemType.CLIP || - projectItem.type == ProjectItemType.FILE) { - - markers = projectItem.getMarkers(); - - if (markers) { - var markerCount = markers.numMarkers; - - if (markerCount) { - for (var thisMarker = markers.getFirstMarker(); thisMarker !== undefined; thisMarker = markers.getNextMarker(thisMarker)) { - var oldColor = thisMarker.getColorByIndex(); - var newColor = oldColor + 1; - if (newColor > 7) { - newColor = 0; - } - thisMarker.setColorByIndex(newColor); - $._PPP_.updateEventPanel("Changed color of marker named \'" + thisMarker.name + "\' from " + oldColor + " to " + newColor + "."); - } - } - } - } else { - $._PPP_.updateEventPanel("Can only add markers to footage items."); - } - } else { - $._PPP_.updateEventPanel("Could not find first projectItem."); - } - } else { - $._PPP_.updateEventPanel("Project is empty."); - } - }, - - changeSeqTimeCodeDisplay: function () { - if (app.project.activeSequence) { - var currentSeqSettings = app.project.activeSequence.getSettings(); - if (currentSeqSettings) { - var oldVidSetting = currentSeqSettings.videoDisplayFormat; - currentSeqSettings.videoDisplayFormat = oldVidSetting + 1; - if (currentSeqSettings.videoDisplayFormat > TIMEDISPLAY_48Timecode) { - currentSeqSettings.videoDisplayFormat = TIMEDISPLAY_24Timecode; - } - app.project.activeSequence.setSettings(currentSeqSettings); - $._PPP_.updateEventPanel("Changed timecode display format for \'" + app.project.activeSequence.name + "\'."); - } - } else { - $._PPP_.updateEventPanel("No active sequence."); - } - }, - - myActiveSequenceChangedFxn: function () { - $._PPP_.updateEventPanel("Active sequence is now " + app.project.activeSequence.name + "."); - }, - - myActiveSequenceSelectionChangedFxn: function () { - var sel = app.project.activeSequence.getSelection(); - $._PPP_.updateEventPanel('Current active sequence = ' + app.project.activeSequence.name + '.'); - $._PPP_.updateEventPanel(sel.length + ' track items selected.'); - for (var i = 0; i < sel.length; i++) { - if (sel[i].name !== 'anonymous') { - $._PPP_.updateEventPanel('Selected item ' + (i + 1) + ' == ' + sel[i].name + '.'); - } - } - }, - - registerActiveSequenceChangedFxn: function () { - var success = app.bind("onActiveSequenceChanged", $._PPP_.myActiveSequenceChangedFxn); - }, - - registerSequenceSelectionChangedFxn: function () { - var success = app.bind('onActiveSequenceSelectionChanged', $._PPP_.myActiveSequenceSelectionChangedFxn); - }, - - enableNewWorldScripting: function () { - app.enableQE(); - - var previousNWValue = qe.getDebugDatabaseEntry("ScriptLayerPPro.EnableNewWorld"); - var previousInternalDOMValue = qe.getDebugDatabaseEntry("dvascripting.EnabledInternalDOM"); - if ((previousNWValue === 'true') && (previousInternalDOMValue === 'true')) { - qe.setDebugDatabaseEntry("ScriptLayerPPro.EnableNewWorld", "false"); - qe.setDebugDatabaseEntry("dvascripting.EnabledInternalDOM", "false"); - $._PPP_.updateEventPanel("ScriptLayerPPro.EnableNewWorld and dvascripting.EnabledInternalDOM are now OFF."); - } else { - qe.setDebugDatabaseEntry("ScriptLayerPPro.EnableNewWorld", "true"); - qe.setDebugDatabaseEntry("dvascripting.EnabledInternalDOM", "true"); - $._PPP_.updateEventPanel("ScriptLayerPPro.EnableNewWorld and dvascripting.EnabledInternalDOM are now ON."); - } - }, - - insertOrAppendToTopTracks: function () { - var seq = app.project.activeSequence; - if (seq) { - var first = app.project.rootItem.children[0]; - if (first) { - var time = seq.getPlayerPosition(); - var newClip = seq.insertClip(first, time, (seq.videoTracks.numTracks - 1), (seq.audioTracks.numTracks - 1)); - if (newClip) { - $._PPP_.updateEventPanel("Inserted " + newClip.name + ", into " + seq.name + "."); - } - } else { - $._PPP_.updateEventPanel("Couldn't locate first projectItem."); - } - } else { - $._PPP_.updateEventPanel("no active sequence."); - } - }, - - closeAllProjectsOtherThanActiveProject: function () { - var viewIDs = app.getProjectViewIDs(); - var closeTheseProjects = []; - for (var a = 0; a < viewIDs.length; a++) { - var thisProj = app.getProjectFromViewID(viewIDs[a]); - if (thisProj.documentID !== app.project.documentID) { - closeTheseProjects[a] = thisProj; - } - } - // Why do this afterward? Because if we close projects in that loop, we change the active project. :) - for (var b = 0; b < closeTheseProjects.length; b++) { - $._PPP_.updateEventPanel("Closed " + closeTheseProjects[b].name); - closeTheseProjects[b].closeDocument(); - } - }, - - countAdjustmentLayersInBin: function (parentItem, arrayOfAdjustmentLayerNames, foundSoFar) { - for (var j = 0; j < parentItem.children.numItems; j++) { - var currentChild = parentItem.children[j]; - if (currentChild) { - if (currentChild.type == ProjectItemType.BIN) { - $._PPP_.countAdjustmentLayersInBin(currentChild, arrayOfAdjustmentLayerNames, foundSoFar); // warning; recursion! - } else { - if (currentChild.isAdjustmentLayer()) { - arrayOfAdjustmentLayerNames[foundSoFar] = currentChild.name; - foundSoFar++; - } - } - } - } - }, - - findAllAdjustmentLayersInProject: function () { - var arrayOfAdjustmentLayerNames = []; - var foundSoFar = 0; - var startingBin = app.project.rootItem; - - $._PPP_.countAdjustmentLayersInBin(startingBin, arrayOfAdjustmentLayerNames, foundSoFar); - if (arrayOfAdjustmentLayerNames.length) { - var remainingArgs = arrayOfAdjustmentLayerNames.length; - var message = remainingArgs + " adjustment layers found: "; - - for (var i = 0; i < arrayOfAdjustmentLayerNames.length; i++) { - message += arrayOfAdjustmentLayerNames[i]; - remainingArgs--; - if (remainingArgs > 1) { - message += ', '; - } - if (remainingArgs === 1) { - message += ", and "; - } - if (remainingArgs === 0) { - message += "."; - } - } - $._PPP_.updateEventPanel(message); - } else { - $._PPP_.updateEventPanel("No adjustment layers found in " + app.project.name + "."); - } - }, - - consolidateDuplicates: function () { - result = app.project.consolidateDuplicates(); - $._PPP_.updateEventPanel("Duplicates consolidated in " + app.project.name + "."); - }, - - closeAllSequences: function () { - var seqList = app.project.sequences; - for (var a = 0; a < seqList.numSequences; a++) { - var currentSeq = seqList[a]; - if (currentSeq) { - currentSeq.close(); - } else { - $._PPP_.updateEventPanel("No sequences from " + app.project.name + " were open."); - } - } - }, - - dumpAllPresets: function () { - var desktopPath = new File("~/Desktop"); - var outputFileName = desktopPath.fsName + $._PPP_.getSep() + 'available_presets.txt'; - var selectedPreset = undefined; - var selectedExporter = undefined; - var exporters = app.encoder.getExporters(); - - var outFile = new File(outputFileName); - - outFile.encoding = "UTF8"; - outFile.open("w", "TEXT", "????"); - - for (var i = 0; i < exporters.length; i++) { - var exporter = exporters[i]; - if (exporter) { - outFile.writeln('-----------------------------------------------'); - outFile.writeln(i + ':' + exporter.name + ' : ' + exporter.classID + ' : ' + exporter.fileType); - var presets = exporter.getPresets(); - if (presets) { - outFile.writeln(presets.length + ' presets found'); - for (var j = 0; j < presets.length; j++) { - var preset = presets[j]; - if (preset) { - outFile.writeln('matchName: ' + preset.matchName + '(' + preset.name + ')'); - if (preset.name.indexOf('TQM') > -1) { - selectedPreset = preset; - selectedExporter = exporter; - outFile.writeln('selected preset = ' + selectedExporter.name + ' : ' + selectedPreset.name); - selectedPreset.writeToFile(desktopPath.fsName + $._PPP_.getSep() + preset.name + ".epr"); - $._PPP_.updateEventPanel("List of available presets saved to desktop as \'available_presets.txt\'"); - } - } - } - } - } - } - desktopPath.close(); - outFile.close(); - }, - - reportSequenceVRSettings: function () { - var seq = app.project.activeSequence; - if (seq) { - var settings = seq.getSettings(); - if (settings) { - $._PPP_.updateEventPanel("===================================================="); - $._PPP_.updateEventPanel("VR Settings for \'" + seq.name + "\':"); - $._PPP_.updateEventPanel(""); - $._PPP_.updateEventPanel(" Horizontal captured view: " + settings.vrHorzCapturedView); - $._PPP_.updateEventPanel(" Vertical captured view: " + settings.vrVertCapturedView); - $._PPP_.updateEventPanel(" Layout: " + settings.Layout); - $._PPP_.updateEventPanel(" Projection: " + settings.vrProjection); - $._PPP_.updateEventPanel(""); - $._PPP_.updateEventPanel("===================================================="); - } - } - }, - - openProjectItemInSource: function () { - var viewIDs = app.getProjectViewIDs(); - if (viewIDs) { - for (var a = 0; a < app.projects.numProjects; a++) { - var currentProject = app.getProjectFromViewID(viewIDs[a]); - if (currentProject) { - if (currentProject.documentID === app.project.documentID) { // We're in the right project! - var selectedItems = app.getProjectViewSelection(viewIDs[a]); - for (var b = 0; b < selectedItems.length; b++) { - var currentItem = selectedItems[b]; - if (currentItem) { - if (currentItem.type !== ProjectItemType.BIN) { // For every selected item which isn't a bin or sequence... - app.sourceMonitor.openProjectItem(currentItem); - } - } else { - $._PPP_.updateEventPanel("No item available."); - } - } - } - } else { - $._PPP_.updateEventPanel("No project available."); - } - } - } else { - $._PPP_.updateEventPanel("No view IDs available."); - } - }, - - reinterpretFootage: function () { - var viewIDs = app.getProjectViewIDs(); - if (viewIDs) { - for (var a = 0; a < app.projects.numProjects; a++) { - var currentProject = app.getProjectFromViewID(viewIDs[a]); - if (currentProject) { - if (currentProject.documentID === app.project.documentID) { // We're in the right project! - var selectedItems = app.getProjectViewSelection(viewIDs[a]); - if (selectedItems) { - for (var b = 0; b < selectedItems.length; b++) { - var currentItem = selectedItems[b]; - if (currentItem) { - if ((currentItem.type !== ProjectItemType.BIN) && - (currentItem.isSequence() === false)) { - var interp = currentItem.getFootageInterpretation(); - if (interp) { - // Note: I made this something terrible, so the change is apparent. - interp.frameRate = 17.868; - interp.pixelAspectRatio = 1.2121; - currentItem.setFootageInterpretation(interp); - } else { - $._PPP_.updateEventPanel("Unable to get interpretation for " + currentItem.name + "."); - } - var mapping = currentItem.getAudioChannelMapping; - if (mapping) { - mapping.audioChannelsType = AUDIOCHANNELTYPE_Stereo; - mapping.audioClipsNumber = 1; - mapping.setMappingForChannel(0, 4); // 1st param = channel index, 2nd param = source index - mapping.setMappingForChannel(1, 5); - currentItem.setAudioChannelMapping(mapping); // submit changed mapping object - } - } - } else { - $._PPP_.updateEventPanel("No project item available."); - } - } - } else { - $._PPP_.updateEventPanel("No items selected."); - } - } - } else { - $._PPP_.updateEventPanel("No project available."); - } - } - } else { - $._PPP_.updateEventPanel("No view IDs available."); - } - }, - - createSubSequence: function () { - - /* Behavioral Note - - createSubSequence() uses track targeting to select clips when there is - no current clip selection, in the sequence. To create a subsequence with - clips on tracks that are currently NOT targeted, either select some clips - (on any track), or temporarily target all desired tracks. - - */ - - var activeSequence = app.project.activeSequence; - if (activeSequence) { - var foundTarget = false; - for (var a = 0; - (a < activeSequence.videoTracks.numTracks) && (foundTarget === false); a++) { - var vTrack = activeSequence.videoTracks[a]; - if (vTrack) { - if (vTrack.isTargeted()) { - foundTarget = true; - } - } - } - // If no targeted track was found, just target the zero-th track, for demo purposes - if (foundTarget === false) { - activeSequence.videotracks[0].setTargeted(true, true); - } - - var cloneAnyway = true; - if ((activeSequence.getInPoint() == NOT_SET) && (activeSequence.getOutPoint() == NOT_SET)) { - cloneAnyway = confirm("No in or out points set; clone entire sequence?", false, "Clone the whole thing?"); - } - if (cloneAnyway) { - var ignoreMapping = confirm("Ignore track mapping?", false, "Ignore track mapping?"); - var newSeq = activeSequence.createSubsequence(ignoreMapping); - // rename newSeq here, as desired. - } - } else { - $._PPP_.updateEventPanel("No active sequence."); - } - }, - - selectAllRetimedClips: function () { - var activeSeq = app.project.activeSequence; - var numRetimedClips = 0; - if (activeSeq) { - var trackGroups = [activeSeq.audioTracks, activeSeq.videoTracks]; - var trackGroupNames = ["audioTracks", "videoTracks"]; - var updateUI = true; - - for (var gi = 0; gi < 2; gi++) { - group = trackGroups[gi]; - for (var ti = 0; ti < group.numTracks; ti++) { - var track = group[ti]; - var clips = track.clips; - for (var ci = 0; ci < clips.numTracks; ci++) { - var clip = clips[ci]; - if (clip.getSpeed() !== 1) { - clip.setSelected(true, updateUI); - numRetimedClips++; - } - } - } - } - $._PPP_.updateEventPanel(numRetimedClips + " retimed clips found."); - } else { - $._PPP_.updateEventPanel("No active sequence."); - } - }, - - selectReversedClips: function () { - var sequence = app.project.activeSequence; - var numReversedClips = 0; - if (sequence) { - var trackGroups = [sequence.audioTracks, sequence.videoTracks]; - var trackGroupNames = ["audioTracks", "videoTracks"]; - var updateUI = true; - - for (var gi = 0; gi < 2; gi++) { - for (var ti = 0; ti < group.numTracks; ti++) { - for (var ci = 0; ci < group[ti].clips.numTracks; ci++) { - var clip = group[ti].clips[ci]; - var isReversed = clip.isSpeedReversed(); - if (isReversed) { - clip.setSelected(isReversed, updateUI); - numReversedClips++; - } - } - } - } - $._PPP_.updateEventPanel(numReversedClips + " reversed clips found."); - } else { - $._PPP_.updateEventPanel("No active sequence."); - } - }, - - logConsoleOutput: function () { - app.enableQE(); - var logFileName = "PPro_Console_output.txt" - var outFolder = Folder.selectDialog("Where do you want to save the log file?"); - if (outFolder) { - var entireOutputPath = outFolder.fsName + $._PPP_.getSep() + logFileName; - var result = qe.executeConsoleCommand("con.openlog " + entireOutputPath); - $._PPP_.updateEventPanel("Log opened at " + entireOutputPath + "."); - } - }, - - closeLog: function () { - app.enableQE(); - qe.executeConsoleCommand("con.closelog"); - }, - - stitch: function (presetPath) { - var viewIDs = app.getProjectViewIDs(); - var allPathsToStitch = ""; - - for (var a = 0; a < app.projects.numProjects; a++) { - var currentProject = app.getProjectFromViewID(viewIDs[a]); - if (currentProject) { - if (currentProject.documentID === app.project.documentID) { // We're in the right project! - var selectedItems = app.getProjectViewSelection(viewIDs[a]); - if (selectedItems.length) { - for (var b = 0; b < selectedItems.length; b++) { - var currentItem = selectedItems[b]; - if (currentItem) { - if ((!currentItem.isSequence()) && (currentItem.type !== ProjectItemType.BIN)) { // For every selected item which isn't a bin or sequence... - allPathsToStitch += currentItem.getMediaPath(); - allPathsToStitch += ";"; - } - } - } - - var AMEString = "var fe = app.getFrontend(); fe.stitchFiles(\"" + allPathsToStitch + "\""; - var addendum = ", \"H.264\", \"" + presetPath + "\", " + "\"(This path parameter is never used)\");"; - - AMEString += addendum; - - // 3. Send Command to AME for Export // - var bt = new BridgeTalk(); - bt.target = 'ame'; - bt.body = AMEString; - bt.send(); - - - - } - } - } - } - }, - - clearESTKConsole: function () { - var bt = new BridgeTalk(); - bt.target = 'estoolkit-4.0'; - bt.body = function () { - app.clc(); - }.toSource() + "()"; - bt.send(); - } -}; diff --git a/pype/premiere/extensions/com.pype.avalon/jsx/batchRenamer.jsx b/pype/premiere/extensions/com.pype.avalon/jsx/batchRenamer.jsx deleted file mode 100644 index 727ec05c2a4..00000000000 --- a/pype/premiere/extensions/com.pype.avalon/jsx/batchRenamer.jsx +++ /dev/null @@ -1,178 +0,0 @@ -/* global app, XMPMeta, ExternalObject, CSXSEvent, Folder */ -/* -------------------------------------- - -. == [ part 0f PyPE CluB ] == .- -_______________.___._____________________ -\______ \__ | |\______ \_ _____/ - | ___// | | | ___/| __)_ - | | \____ | | | | \ - |____| / ______| |____| /_______ / - \/ \/ - .. __/ CliP R3N4M3R \__ .. -*/ - -// variable br is defined in pypeAvalon.jsx -br = { - getSelectedVideoTrackItems: function () { - var seq = app.project.activeSequence; - var selected = []; - var videoTracks = seq.videoTracks; - var numOfVideoTracks = videoTracks.numTracks; - - // VIDEO CLIPS IN SEQUENCES - for (var l = 0; l < numOfVideoTracks; l++) { - var videoTrack = seq.videoTracks[l]; - if (videoTrack.isTargeted()) { - $.writeln(videoTrack.name); - var numOfClips = videoTrack.clips.numTracks; - for (var m = 0; m < numOfClips; m++) { - var clip = videoTrack.clips[m]; - - selected.push({ - 'name': clip.name, - 'clip': clip, - 'sequence': seq, - 'videoTrack': videoTrack - }); - } - } - } - var names = []; - var items = {}; - var sorted = []; - for (var c = 0; c < selected.length; c++) { - items[selected[c].name] = selected[c]; - names.push(selected[c].name); - } - names.sort(); - - for (var cl = 0; cl < names.length; cl++) { - sorted.push(items[names[cl]]); - } - return sorted; - }, - - /** - * Set Pype metadata into sequence metadata using XMP. - * This is `hackish` way to get over premiere lack of addressing unique clip on timeline, - * so we cannot store data directly per clip. - * - * @param {Object} sequence - sequence object - * @param {Object} data - to be serialized and saved - */ - setSequencePypeMetadata: function (sequence, data) { // eslint-disable-line no-unused-vars - var kPProPrivateProjectMetadataURI = 'http://ns.adobe.com/premierePrivateProjectMetaData/1.0/'; - var metadata = sequence.projectItem.getProjectMetadata(); - var pypeData = 'pypeData'; - var xmp = new XMPMeta(metadata); - - app.project.addPropertyToProjectMetadataSchema(pypeData, 'Pype Data', 2); - - xmp.setProperty(kPProPrivateProjectMetadataURI, pypeData, JSON.stringify(data)); - - var str = xmp.serialize(); - sequence.projectItem.setProjectMetadata(str, [pypeData]); - - // test - var newMetadata = sequence.projectItem.getProjectMetadata(); - var newXMP = new XMPMeta(newMetadata); - var found = newXMP.doesPropertyExist(kPProPrivateProjectMetadataURI, pypeData); - if (!found) { - app.setSDKEventMessage('metadata not set', 'error'); - } - }, - - /** - * Get Pype metadata from sequence using XMP. - * @param {Object} sequence - * @return {Object} - */ - getSequencePypeMetadata: function (sequence) { // eslint-disable-line no-unused-vars - var kPProPrivateProjectMetadataURI = 'http://ns.adobe.com/premierePrivateProjectMetaData/1.0/'; - var metadata = sequence.projectItem.getProjectMetadata(); - var pypeData = 'pypeData'; - var pypeDataN = 'Pype Data'; - var xmp = new XMPMeta(metadata); - app.project.addPropertyToProjectMetadataSchema(pypeData, pypeDataN, 2); - var pypeDataValue = xmp.getProperty(kPProPrivateProjectMetadataURI, pypeData); - $.writeln('pypeDataValue'); - $.writeln(pypeDataValue); - if (pypeDataValue === undefined) { - var pyMeta = { - clips: {}, - tags: {} - }; - br.setSequencePypeMetadata(sequence, pyMeta); - pypeDataValue = xmp.getProperty(kPProPrivateProjectMetadataURI, pypeData); - return br.getSequencePypeMetadata(sequence); - } else { - return JSON.parse(pypeDataValue); - } - }, - renameTargetedTextLayer: function (data) { - $.writeln(data); - var selected = br.getSelectedVideoTrackItems(); - - var seq = app.project.activeSequence; - var metadata = br.getSequencePypeMetadata(seq); - - var startCount = 10; - var stepCount = 10; - var padding = 3; - var newItems = {}; - var episode = data.ep; - var episodeSuf = data.epSuffix; - var shotPref = 'sh'; - var count = 0; - var seqCheck = ''; - - for (var c = 0; c < selected.length; c++) { - // fill in hierarchy if set - var parents = []; - var hierarchy = []; - var name = selected[c].name; - var sequenceName = name.slice(0, 5); - var shotNum = Number(name.slice((name.length - 3), name.length)); - - // if (sequenceName !== seqCheck) { - // seqCheck = sequenceName; - // count = 0; - // }; - // - // var seqCount = (count * stepCount) + startCount; - // count += 1; - - var newName = episode + sequenceName + shotPref + (shotNum).pad(padding); - $.writeln(newName); - selected[c].clip.name = newName; - - parents.push({ - 'entityType': 'episode', - 'entityName': episode + '_' + episodeSuf - }); - hierarchy.push(episode + '_' + episodeSuf); - - parents.push({ - 'entityType': 'sequence', - 'entityName': episode + sequenceName - }); - hierarchy.push(episode + sequenceName); - - newItems[newName] = { - 'parents': parents, - 'hierarchy': hierarchy.join('/') - }; - } - - metadata.clips = newItems; - br.setSequencePypeMetadata(seq, metadata); - return JSON.stringify(metadata); - } -}; - -Number.prototype.pad = function (size) { - var s = String(this); - while (s.length < (size || 2)) { - s = "0" + s; - } - return s; -} diff --git a/pype/premiere/extensions/com.pype.avalon/jsx/pype.jsx b/pype/premiere/extensions/com.pype.avalon/jsx/pype.jsx deleted file mode 100644 index f2ca65fa4ec..00000000000 --- a/pype/premiere/extensions/com.pype.avalon/jsx/pype.jsx +++ /dev/null @@ -1,1125 +0,0 @@ -/* global app, qe, $, ProjectItemType */ -/* - .____ _ ___ .____.______ ---- - - -- / . \// // . \ ___/ --- ---- - - - - --- --- / ____/ __// ____/ /_/ --- - -- --- - /__/ /___/ /__/ /______/ - ._- -=[ PyPe 4 3veR ]=- -_. -*/ - -if (ExternalObject.AdobeXMPScript === undefined) { - ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript'); -} - -// variable pype is defined in pypeAvalon.jsx -pype = { - addNewTrack: function (numTracks) { - app.enableQE(); - var sequence = app.project.activeSequence; - var activeSequence = qe.project.getActiveSequence(); - activeSequence.addTracks(numTracks, sequence.videoTracks.numTracks, 0) - - for (var t = 0; t < sequence.videoTracks.numTracks; t++) { - var videoTrack = sequence.videoTracks[t]; - var trackName = videoTrack.name - var trackTarget = videoTrack.isTargeted(); - // $.writeln(trackTarget); - sequence.videoTracks[t].setTargeted(false, true); - trackTarget = videoTrack.isTargeted(); - // $.writeln(trackTarget); - // $.writeln(videoTrack); - } - }, - - searchForBinWithName: function (nameToFind, folderObject) { - // deep-search a folder by name in project - var deepSearchBin = function (inFolder) { - if (inFolder && inFolder.name === nameToFind && inFolder.type === 2) { - return inFolder; - } else { - for (var i = 0; i < inFolder.children.numItems; i++) { - if (inFolder.children[i] && inFolder.children[i].type === 2) { - var foundBin = deepSearchBin(inFolder.children[i]); - if (foundBin) return foundBin; - } - } - } - return undefined; - }; - if (folderObject === undefined) { - return deepSearchBin(app.project.rootItem); - } else { - return deepSearchBin(folderObject); - } - - }, - - createDeepBinStructure: function (hierarchyString) { - var parents = hierarchyString.split('/'); - - // search for the created folder - var currentBin = pype.searchForBinWithName(parents[0]); - // create bin if doesn't exists - if (currentBin === undefined) { - currentBin = app.project.rootItem.createBin(parents[0]) - }; - for (var b = 1; b < parents.length; b++) { - var testBin = pype.searchForBinWithName(parents[b], currentBin); - if (testBin === undefined) { - currentBin = currentBin.createBin(parents[b]); - } else { - currentBin = testBin; - } - } - return currentBin - }, - - insertBinClipToTimeline: function (binClip, time, trackOrder, numTracks, origNumTracks) { - var seq = app.project.activeSequence; - var numVTracks = seq.videoTracks.numTracks; - - var addInTrack = (numTracks === 1) ? - (origNumTracks) : - (numVTracks - numTracks + trackOrder); - $.writeln("\n___name: " + binClip.name); - $.writeln("numVTracks: " + numVTracks + ", trackOrder: " + trackOrder + ", numTracks: " + numTracks + ", origNumTracks: " + origNumTracks + ", addInTrack: " + addInTrack); - - var targetVTrack = seq.videoTracks[addInTrack]; - - if (targetVTrack) { - targetVTrack.insertClip(binClip, time); - } - }, - /** - * Return instance representation of clip imported into bin - * @param data {object} - has to have at least two attributes `clips` and `binHierarchy` - * @return {Object} - */ - importFiles: function (data) { - // remove all empty tracks - app.enableQE(); - var activeSequence = qe.project.getActiveSequence(); - activeSequence.removeEmptyVideoTracks(); - activeSequence.removeEmptyAudioTracks(); - - if (app.project) { - if (data !== undefined) { - var pathsToImport = []; - var namesToGetFromBin = []; - var namesToSetToClips = []; - var origNumTracks = app.project.activeSequence.videoTracks.numTracks; - // TODO: for now it always creates new track and adding it into it - pype.addNewTrack(data.numTracks); - - // get all paths and names list - var key = ''; - for (key in data.clips) { - var path = data.clips[key]['data']['path']; - var fileName = path.split('/'); - if (fileName.length <= 1) { - fileName = path.split('\\'); - }; - fileName = fileName[fileName.length - 1] - pathsToImport.push(path); - namesToGetFromBin.push(fileName); - namesToSetToClips.push(key) - } - - // create parent bin object - var parent = pype.createDeepBinStructure(data.binHierarchy); - - // check if any imported clips are in the bin - if (parent.children.numItems > 0) { - var refinedListForImport = []; - // loop pathsToImport - var binItemNames = []; - for (var c = 0; c < parent.children.numItems; c++) { - binItemNames.push(parent.children[c].name) - } - - // loop formated clip names to be imported - for (var p = 0; p < namesToSetToClips.length; p++) { - // check if the clip is not in bin items alrady - if (!include(binItemNames, namesToSetToClips[p])) { - app.project.importFiles([pathsToImport[p]], - 1, // suppress warnings - parent, - 0); // import as numbered stills - - for (var pi = 0; pi < parent.children.numItems; pi++) { - - if (namesToGetFromBin[p] === parent.children[pi].name) { - parent.children[pi].name = namesToSetToClips[p]; - var start = data.clips[namesToSetToClips[p]]['parentClip']['start'] - pype.insertBinClipToTimeline(parent.children[pi], start, data.clips[namesToSetToClips[p]]['parentClip']['trackOrder'], data.numTracks, origNumTracks); - } - } - } else { // if the bin item already exist just update the path - // loop children in parent bin - for (var i = 0; i < parent.children.numItems; i++) { - if (namesToSetToClips[p] === parent.children[i].name) { - $.writeln("__namesToSetToClips[p]__: " + namesToSetToClips[p]) - parent.children[i].changeMediaPath(pathsToImport[p]); - // clip exists and we can update path - $.writeln("____clip exists and updating path"); - } - } - } - } - - } else { - - app.project.importFiles(pathsToImport, - 1, // suppress warnings - parent, - 0); // import as numbered stills - for (var i = 0; i < parent.children.numItems; i++) { - parent.children[i].name = namesToSetToClips[i]; - var start = data.clips[namesToSetToClips[i]]['parentClip']['start'] - pype.insertBinClipToTimeline(parent.children[i], start, data.clips[namesToSetToClips[i]]['parentClip']['trackOrder'], data.numTracks, origNumTracks); - } - - return - }; - } else { - alert('Missing data for clip insertion', 'error'); - return false - } - } - // remove all empty tracks - activeSequence.removeEmptyVideoTracks(); - activeSequence.removeEmptyAudioTracks(); - }, - setEnvs: function (env) { - for (key in env) { - // $.writeln((key + ': ' + env[key])); - $.setenv(key, env[key]) - }; - }, - - importClips: function (obj) { - app.project.importFiles(obj.paths); - return JSON.stringify(obj); - }, - - convertPathString: function (path) { - return path.replace( - new RegExp('\\\\', 'g'), '/').replace(new RegExp('//\\?/', 'g'), '').replace( - new RegExp('/', 'g'), '\\').replace('UNC', '\\');; - }, - - getProjectFileData: function () { - app.enableQE(); - var projPath = new File(app.project.path) - var obj = { - projectfile: app.project.name, - projectpath: pype.convertPathString(projPath.fsName), - projectdir: pype.convertPathString(app.project.path).split('\\').slice(0, -1).join('\\') - }; - return JSON.stringify(obj); - }, - - getSequences: function () { - var project = app.project; - var sequences = []; - for (var i = 0; i < project.sequences.numSequences; i++) { - var seq = project.sequences[i]; - seq.clipNames = []; - sequences[i] = seq; - pype.log('sequences[i] id: ' + project.sequences[i].sequenceID); - } - - var obj = { - sequences: sequences - }; - return JSON.stringify(obj); - }, - - getSequenceItems: function (seqs) { - app.enableQE(); - qe.project.init(); - var sequences = seqs; - // pype.log('getSequenceItems sequences obj from app: ' + sequences); - - var rootFolder = app.project.rootItem; - var binCounter = -1; - var rootSeqCounter = -1; // count sequences in root folder - - // walk through root folder of project to differentiate between bins, sequences and clips - for (var i = 0; i < rootFolder.children.numItems; i++) { - // pype.log('\nroot item at ' + i + " is " + rootFolder.children[i].name + " of type " + rootFolder.children[i].type); - var item = rootFolder.children[i]; - // pype.log('item has video tracks? ' + item.videoTracks); - if (item.type === 2) { // bin - binCounter++; - walkBins(item, 'root', binCounter); - } else if (item.type === 1 && !item.getMediaPath()) { // sequence OR other type of object - // pype.log('\nObject of type 1 in root: ' + typeof item + ' ' + item.name); - if (objectIsSequence(item)) { // objects of type can also be other objects such as titles, so check if it really is a sequence - // pype.log('\nSequence in root: ' + item.name ); - rootSeqCounter++; - var seq = qe.project.getSequenceAt(rootSeqCounter); - // pype.log('\nSequence in root, guid: ' + seq ); - for (var property in seq) { - if (seq.hasOwnProperty(property)) { - // pype.log('\nSequence in root: ' + seq ); - // pype.log('qe sequence prop: ' + property ); - } - } - getClipNames(seq, sequences); - } - } - } - - function objectIsSequence() { - var isSequence = false; - - for (var s = 0; s < app.project.sequences.numSequences; s++) { - if (item.name === app.project.sequences[s].name) { - isSequence = true; - } - } - - return isSequence; - } - - // walk through bins recursively - function walkBins(item, source, rootBinCounter) { - app.enableQE(); - // pype.log('\nget clips for bin ' + item.name ); - - var bin; - if (source === 'root') { // bin in root folder - bin = qe.project.getBinAt(rootBinCounter); - } else { // bin in other bin - bin = item; - - for (var i = 0; i < bin.numBins; i++) { // if bin contains bin(s) walk through them - walkBins(bin.getBinAt(i)); - } - // pype.log('Bin ' + bin.name + ' has ' + bin.numSequences + ' sequences ' ); - // var seqCounter = -1; - for (var j = 0; j < bin.numSequences; j++) { - // if(objectIsSequence(item)) {//objects of type can also be other objects such as titles, so check if it really is a sequence? - // not needed because getSequenceAt apparently only looks at sequences already? - var seq = bin.getSequenceAt(j); - // pype.log('\nSequence in bin, guid: ' + seq.guid ); - getClipNames(seq, sequences); - } - } - } - - // walk through sequences and video & audiotracks to find clip names in sequences - function getClipNames(seq, sequences) { - for (var k = 0; k < sequences.length; k++) { - // pype.log('getClipNames seq.guid ' + seq.guid ); - // pype.log(' getClipNames sequences[k].id ' + sequences[k].sequenceID ); - if (seq.guid === sequences[k].sequenceID) { - // pype.log('Sequence ' + seq.name + ' has ' + app.project.sequences[k].videoTracks.numTracks +' video tracks' ); - // pype.log('Sequence ' + seq.name + ' has ' + app.project.sequences[k].audioTracks.numTracks +' audio tracks' ); - - // VIDEO CLIPS IN SEQUENCES - for (var l = 0; l < sequences[k].videoTracks.numTracks; l++) { - var videoTrack = seq.getVideoTrackAt(l); - // pype.log(seq.name + ' has video track '+ videoTrack.name + ' at index ' + l); - var clipCounter = 0; - var numOfClips = app.project.sequences[k].videoTracks[l].clips.numTracks; - // pype.log('\n' + bin.name + ' ' + seq.name + ' ' + videoTrack.name + ' has ' + numOfClips + ' clips'); - for (var m = 0; m < numOfClips; m++) { - // var clip = app.project.sequences[k].videoTracks[l].clips[m]; - // pype.log('clips in video tracks: ' + m + ' - ' + clip); //TrackItem, doesn't have name property - // if a clip was deleted and another one added, the index of the new one is one or more higher - while (clipCounter < numOfClips) { // undefined because of old clips - if (videoTrack.getItemAt(m).name) { - clipCounter++; - // pype.log('getClipNames ' + seq.name + ' ' + videoTrack.name + ' has ' + videoTrack.getItemAt(m).name); //Object - - for (var s = 0; s < sequences.length; s++) { - if (seq.guid === sequences[s].sequenceID) { - sequences[s].clipNames.push(videoTrack.getItemAt(m).name); - } - } - } - m++; - } - } - } - // pype.log('jsx after video loop clipsInSequences:' + clipsInSequences); - - // AUDIO CLIPS IN SEQUENCES - for (var l = 0; l < sequences[k].audioTracks.numTracks; l++) { - var audioTrack = seq.getAudioTrackAt(l); - // pype.log(bin.name + ' ' + seq.name + ' has audio track '+ audioTrack.name + ' at index ' + l); - // pype.log('\n' + bin.name + ' ' + seq.name + ' ' + audioTrack.name + ' has ' + app.project.sequences[k].audioTracks[l].clips.numTracks + ' clips'); - var clipCounter = 0; - var numOfClips = app.project.sequences[k].audioTracks[l].clips.numTracks; - - for (var m = 0; m < numOfClips; m++) { - var clip = app.project.sequences[k].audioTracks[l].clips[m]; - // pype.log('clips in audio tracks: ' + m + ' - ' + clip); - // if a clip was deleted and another one added, the index of the new one is one or more higher - while (clipCounter < numOfClips) { // undefined because of old clips - if (audioTrack.getItemAt(m).name) { - clipCounter++; - // pype.log(seq.name + ' ' + audioTrack.name + ' has ' + audioTrack.getItemAt(m).name); - - for (var s = 0; s < sequences.length; s++) { - if (seq.guid === sequences[s].sequenceID) { - sequences[s].clipNames.push(audioTrack.getItemAt(m).name); - } - } - } - m++; - } - } - } - } // end if - } // end for - } // end getClipNames - - pype.log('sequences returned:' + sequences); - // return result to ReplaceService.js - var obj = { - data: sequences - }; - // pype.log('jsx getClipNames obj:' + obj); - return JSON.stringify(obj); - }, - - // getSequenceItems(); - getProjectItems: function () { - var projectItems = []; - app.enableQE(); - qe.project.init(); - - var rootFolder = app.project.rootItem; - // walk through root folder of project to differentiate between bins, sequences and clips - for (var i = 0; i < rootFolder.children.numItems; i++) { - // pype.log('\nroot item at ' + i + " is of type " + rootFolder.children[i].type); - var item = rootFolder.children[i]; - - if (item.type === 2) { // bin - // pype.log('\n' ); - pype.getProjectItems.walkBins(item); - } else if (item.type === 1 && item.getMediaPath()) { // clip in root - // pype.log('Root folder has ' + item + ' ' + item.name); - projectItems.push(item); - } - } - - // walk through bins recursively - function walkBins(bin) { // eslint-disable-line no-unused-vars - app.enableQE(); - - // $.writeln('bin.name + ' has ' + bin.children.numItems); - for (var i = 0; i < bin.children.numItems; i++) { - var object = bin.children[i]; - // pype.log(bin.name + ' has ' + object + ' ' + object.name + ' of type ' + object.type + ' and has mediapath ' + object.getMediaPath() ); - if (object.type === 2) { // bin - // pype.log(object.name + ' has ' + object.children.numItems ); - for (var j = 0; j < object.children.numItems; j++) { - var obj = object.children[j]; - if (obj.type === 1 && obj.getMediaPath()) { // clip in sub bin - // pype.log(object.name + ' has ' + obj + ' ' + obj.name ); - projectItems.push(obj); - } else if (obj.type === 2) { // bin - walkBins(obj); - } - } - } else if (object.type === 1 && object.getMediaPath()) { // clip in bin in root - // pype.log(bin.name + ' has ' + object + ' ' + object.name ); - projectItems.push(object); - } - } - } - pype.log('\nprojectItems:' + projectItems.length + ' ' + projectItems); - return projectItems; - }, - - replaceClips: function (obj) { - pype.log('num of projectItems:' + projectItems.length); - var hiresVOs = obj.hiresOnFS; - for (var i = 0; i < hiresVOs.length; i++) { - pype.log('hires vo name: ' + hiresVOs[i].name); - pype.log('hires vo id: ' + hiresVOs[i].id); - pype.log('hires vo path: ' + hiresVOs[i].path); - pype.log('hires vo replace: ' + hiresVOs[i].replace); - - for (var j = 0; j < projectItems.length; j++) { - // pype.log('projectItem id: ' + projectItems[j].name.split(' ')[0] + ' ' + hiresVOs[i].id + ' can change path ' + projectItems[j].canChangeMediaPath() ); - if (projectItems[j].name.split(' ')[0] === hiresVOs[i].id && hiresVOs[i].replace && projectItems[j].canChangeMediaPath()) { - pype.log('replace: ' + projectItems[j].name + ' with ' + hiresVOs[i].name); - projectItems[j].name = hiresVOs[i].name; - projectItems[j].changeMediaPath(hiresVOs[i].path); - } - } - } - }, - - getActiveSequence: function () { - return app.project.activeSequence; - }, - - getImageSize: function () { - return { - h: app.project.activeSequence.frameSizeHorizontal, - v: app.project.activeSequence.frameSizeVertical - }; - }, - getInOutOfAll: function () { - var seq = app.project.activeSequence; - var points = []; - var output = []; - - // VIDEO CLIPS IN SEQUENCES - for (var l = 0; l < seq.videoTracks.numTracks; l++) { - var numOfClips = seq.videoTracks[l].clips.numTracks; - // $.writeln('\n' + seq.name + ' ' + seq.videoTracks[l].name + ' has ' + numOfClips + ' clips'); - for (var m = 0; m < numOfClips; m++) { - var clip = seq.videoTracks[l].clips[m]; - points.push(Math.ceil(clip.start.seconds * 1000) / 1000); - points.push(Math.ceil(clip.end.seconds * 1000) / 1000); - } - }; - - points.sort(function (a, b) { - return a - b - }); - - output.push(points[0]); - output.push(points[points.length - 1]); - - return output; - }, - getSelectedItems: function () { - var seq = app.project.activeSequence; - var selected = []; - - // VIDEO CLIPS IN SEQUENCES - for (var l = 0; l < seq.videoTracks.numTracks; l++) { - var numOfClips = seq.videoTracks[l].clips.numTracks; - // $.writeln('\n' + seq.name + ' ' + seq.videoTracks[l].name + ' has ' + numOfClips + ' clips'); - for (var m = 0; m < numOfClips; m++) { - var clip = seq.videoTracks[l].clips[m]; - if (clip.isSelected()) { - selected.push({ - 'clip': clip, - 'sequence': seq, - 'videoTrack': seq.videoTracks[l], - 'trackOrder': l - }); - } - } - } - return selected; - }, - dumpPublishedInstancesToMetadata: function (resultedPyblishJsonData) { - $.writeln(resultedPyblishJsonData.instances); - var instances = resultedPyblishJsonData.instances; - var pypeData = pype.loadSequenceMetadata(app.project.activeSequence); - for (var i = 0; i < instances.length; i++) { - $.writeln(instances[i].label) - // process instances - // check if asset in metadata - // add it to sequence metadata - if (instances[i].family !== "projectfile") { - var data = {}; - data.family = instances[i].family; - data.ftrackShotId = instances[i].ftrackShotId; - data.template = instances[i].template; - data.version = instances[i].version; - data.ftrackTaskID = instances[i].ftrackTask.substring(6, (instances[i].ftrackTask.length - 2)); - data.representation = instances[i].jsonData.representations[ - instances[i].families.families[0] - ]; - // getting published path from transfers - var transfers = instances[i].transfers.transfers; - for (var t = 0; t < transfers.length; t++) { - for (var tt = 0; tt < transfers[t].length; tt++) { - var subsetR = new RegExp(data.subset); - var reprR = new RegExp(data.representation.representation); - // selecting published path - if (subsetR.test(transfers[t][tt]) && reprR.test(transfers[t][tt])) { - data.absPath = transfers[t][tt]; - }; - }; - }; - // add all created publishe data into sequence metadata object - var subsetData = {}; - if (pypeData.clips[instances[i].asset].published === undefined) { - subsetData[instances[i].subset] = data; - pypeData.clips[instances[i].asset].published = subsetData; - } else { - pypeData.clips[instances[i].asset].published[instances[i].subset] = data; - }; - - }; - }; - - //dumping all data back to sequence metadata - pype.dumpSequenceMetadata(pypeData, app.project.activeSequence) - }, - dumpSequenceMetadata: function (data, sequence) { - if (sequence === undefined) { - var sequence = app.project.activeSequence; - }; - var kPProPrivateProjectMetadataURI = "http://ns.adobe.com/premierePrivateProjectMetaData/1.0/"; - var metadata = sequence.projectItem.getProjectMetadata(); - var pypeData = "pypeData" - var xmp = new XMPMeta(metadata); - app.project.addPropertyToProjectMetadataSchema(pypeData, "Pype Data", 2); - - - xmp.setProperty(kPProPrivateProjectMetadataURI, pypeData, JSON.stringify(data)); - - var str = xmp.serialize(); - - sequence.projectItem.setProjectMetadata(str, [pypeData]); - $.writeln('________________________') - $.writeln(JSON.stringify(data)) - $.writeln('________________________') - }, - - loadSequenceMetadata: function (sequence) { - var kPProPrivateProjectMetadataURI = "http://ns.adobe.com/premierePrivateProjectMetaData/1.0/"; - var metadata = sequence.projectItem.getProjectMetadata(); - var pypeData = "pypeData" - var xmp = new XMPMeta(metadata); - var pypeDataValue = xmp.getProperty(kPProPrivateProjectMetadataURI, pypeData); - - return JSON.parse(pypeDataValue); - }, - - /** - * Return instance representation of clip - * @param clip {object} - index of clip on videoTrack - * @param sequence {object Sequence} - Sequence clip is in - * @param videoTrack {object VideoTrack} - VideoTrack clip is in - * @return {Object} - */ - getClipAsInstance: function (clip, sequence, videoTrack, pypeData) { - // var clip = sequence.videoTracks.clips[clipIdx] - if ((clip.projectItem.type !== ProjectItemType.CLIP) && - (clip.mediaType !== 'Video')) { - return false; - } - var presets = pype.getPresets(); - var pdClips = pypeData.clips; - var hierarchy; - var parents; - - if (pdClips[clip.name]) { - parents = pdClips[clip.name].parents; - hierarchy = pdClips[clip.name].hierarchy; - } - - if (hierarchy === null) { - alert('First you need to rename clip sequencially with hierarchy!\nUse `Pype Rename` extension', 'No hierarchy data available at clip ' + clip.name + '!', 'error'); - return; - }; - - var interpretation = clip.projectItem.getFootageInterpretation(); - var instance = {}; - instance['publish'] = true; - instance['family'] = 'clip'; - instance['name'] = clip.name; - instance['hierarchy'] = hierarchy; - instance['parents'] = parents; - instance['representations'] = presets.rules_tasks.representations; - // metadata - var metadata = {}; - // TODO: how to get colorspace clip info - metadata['colorspace'] = 'bt.709'; - var settings = sequence.getSettings(); - var sequenceSize = pype.getImageSize(); - metadata['ppro.videoTrack.name'] = videoTrack.name; - metadata['ppro.sequence.name'] = sequence.name; - metadata['ppro.source.fps'] = (1 / interpretation.frameRate); - metadata['ppro.timeline.fps'] = (1 / settings.videoFrameRate.seconds); - metadata['ppro.source.path'] = pype.convertPathString(clip.projectItem.getMediaPath()); - metadata['ppro.format.width'] = sequenceSize.h; - metadata['ppro.format.height'] = sequenceSize.v; - metadata['ppro.format.pixelaspect'] = interpretation.pixelAspectRatio; - metadata['ppro.source.start'] = clip.inPoint.seconds; - metadata['ppro.source.end'] = clip.outPoint.seconds; - metadata['ppro.source.duration'] = clip.duration.seconds; - metadata['ppro.clip.start'] = clip.start.seconds; - metadata['ppro.clip.end'] = clip.end.seconds; - - // set metadata to instance - instance['metadata'] = metadata; - return instance; - }, - getClipsForLoadingSubsets: function (subsetName) { - // instances - var sequence = app.project.activeSequence; - var settings = sequence.getSettings(); - var instances = {}; - var numTracks = []; - var orders = []; - var selected = pype.getSelectedItems(); - for (var s = 0; s < selected.length; s++) { - orders.push(selected[s].trackOrder); - } - var orderStart = Math.min.apply(null, orders); - $.writeln("__orderStart__: " + orderStart) - - for (var s = 0; s < selected.length; s++) { - var selClipName = selected[s].clip.name; - $.writeln(selClipName); - var nameSplit = selClipName.split('_'); - - if (nameSplit.length > 0) { - $.writeln(nameSplit); - $.writeln(subsetName); - if (include(nameSplit, subsetName)) { - selClipName = nameSplit[0]; - } - } - var clip = {}; - clip.start = selected[s].clip.start.seconds; - clip.end = selected[s].clip.end.seconds; - clip.fps = (1 / settings.videoFrameRate.seconds); - clip.trackOrder = selected[s].trackOrder - orderStart; - if (clip !== false) { - instances[selClipName] = clip; - if (!include(numTracks, selected[s].trackOrder)) { - numTracks.push(selected[s].trackOrder) - } - } - } - var instanceSorted = {}; - var sorting = []; - for (var key in instances) { - sorting.push(key); - } - sorting.sort(); - for (var k = 0; k < sorting.length; k++) { - instanceSorted[sorting[k]] = instances[sorting[k]]; - } - return JSON.stringify([instanceSorted, numTracks.length]); - }, - createSubsetClips: function (data) { - var pypeData = pype.loadSequenceMetadata(app.project.activeSequence) - // instances - var instances = {}; - var selected = pype.getSelectedItems(); - for (var s = 0; s < selected.length; s++) { - var clip = {}; - clip.start = selected[s].clip.start.seconds; - clip.end = selected[s].clip.end.seconds; - if (clip !== false) { - instances[clip.name] = clip; - } - } - return JSON.stringify(instances); - }, - getSelectedClipsAsInstances: function () { - // get project script version and add it into clip instance data - var version = pype.getWorkFileVersion(); - - var pypeData = pype.loadSequenceMetadata(app.project.activeSequence) - if (pypeData == null) { - alert('First you need to rename clips sequencially with hierarchy!\nUse `Pype Rename` extension', 'No hierarchy data available!', 'error'); - return; - }; - // instances - var instances = []; - var selected = pype.getSelectedItems(); - for (var s = 0; s < selected.length; s++) { - var instance = pype.getClipAsInstance( - selected[s].clip, - selected[s].sequence, - selected[s].videoTrack, - pypeData - ); - if (instance !== false) { - instance.version = version; - instances.push(instance); - } - }; - - // adding project file instance - var projectFileData = JSON.parse(pype.getProjectFileData()); - var projectFileInstance = projectFileData; - projectFileInstance.representations = { - projectfile: { - representation: 'prproj' - } - }; - projectFileInstance.name = projectFileData.projectfile.split('.')[0]; - projectFileInstance.publish = true; - projectFileInstance.family = 'projectfile'; - projectFileInstance.version = version; - instances.push(projectFileInstance); - - return instances; - }, - getPresets: function () { - var templ_path = pype.convertPathString($.getenv("PYPE_STUDIO_TEMPLATES")); - var preset_path = templ_path + "/presets/premiere"; - var presets = {}; - var preset_files = Folder(preset_path).getFiles(); - for (var f = 0; f < preset_files.length; f++) { - var sliced_file = ('' + preset_files[f]).split('/') - var file_name = sliced_file.slice((sliced_file.length - 2, -1)) - var name = ('' + file_name).split('.')[0] - var file = new File(preset_files[f]); - file.encoding = "UTF8"; - file.open("r", "TEXT", "????"); - presets[name] = JSON.parse(file.read()); - } - return presets - }, - - /** - * Return request json data object with instances for pyblish - * @param stagingDir {string} - path to temp directory - * @return {json string} - */ - getPyblishRequest: function (stagingDir, audioOnly) { - var sequence = app.project.activeSequence; - var settings = sequence.getSettings(); - var request = { - stagingDir: stagingDir, - currentFile: pype.convertPathString(app.project.path), - framerate: (1 / settings.videoFrameRate.seconds), - host: $.getenv('AVALON_APP'), - hostVersion: $.getenv('AVALON_APP_NAME').split('_')[1], - cwd: pype.convertPathString(app.project.path).split('\\').slice(0, -1).join('\\') - }; - var sendInstances = []; - var instances = pype.getSelectedClipsAsInstances(); - if (audioOnly) { - for (var i = 0; i < instances.length; i++) { - var representations = instances[i].representations; - var newRepr = {}; - for (var key in representations) { - var _include = ['audio', 'thumbnail', 'projectfile']; - if (include(_include, key)) { - newRepr[key] = representations[key]; - } - } - instances[i].representations = newRepr; - sendInstances.push(instances[i]); - } - } else { - sendInstances = instances; - } - request['instances'] = sendInstances; - return JSON.stringify(request); - }, - - convertSecToTimecode: function (timeSec, fps) { - var ceiled = Math.round(timeSec * 100) / 100; - var parts = ('' + ceiled).split('.'); - var dec = Number(parts[1]); - var main = Number(parts[0]); - var sec; - var frames = (Number(('' + ((dec * fps) / 100)).split('.')[0])).pad(2); - if (main > 59) { - sec = (Math.round(((Number(('' + (Math.round((main / 60) * 100) / 100).toFixed(2)).split('.')[1]) / 100) * 60))).pad(2); - if (sec === 'NaN') { - sec = '00'; - }; - } else { - sec = main; - }; - var min = (Number(('' + (main / 60)).split('.')[0])).pad(2); - var hov = (Number(('' + (main / 3600)).split('.')[0])).pad(2); - - return hov + ":" + min + ":" + sec + ":" + frames; - }, - exportThumbnail: function (name, family, version, outputPath, time, fps) { - app.enableQE(); - var activeSequence = qe.project.getActiveSequence(); // note: make sure a sequence is active in PPro UI - var file = name + '_' + - family + - '_v' + version + - '.jpg'; - var fullPathToFile = outputPath + - $._PPP_.getSep() + - file; - var expJPEG = activeSequence.exportFrameJPEG( - pype.convertSecToTimecode(time, fps), - pype.convertPathString(fullPathToFile).split('/').join($._PPP_.getSep()) - ); - return file; - }, - encodeRepresentation: function (request) { - var waitFile = ''; - var sequence = app.project.activeSequence - // get original timeline in out points - var defaultTimelinePointValue = -400000 - var origInPoint = Math.ceil(sequence.getInPoint() * 100) / 100; - var origOutPoint = Math.ceil(sequence.getOutPoint() * 100) / 100; - if (origInPoint == defaultTimelinePointValue) { - var allInOut = pype.getInOutOfAll(); - origInPoint = allInOut[0]; - origOutPoint = allInOut[1]; - }; - - // instances - var instances = request['instances'] - for (var i = 0; i < instances.length; i++) { - // generate data for instance's representations - // loop representations of instance and sent job to encoder - var representations = instances[i].representations; - instances[i].files = []; - for (var key in representations) { - - // send render jobs to encoder - var exclude = ['projectfile', 'thumbnail']; - if (!include(exclude, key)) { - instances[i].files.push(pype.render( - request.stagingDir, - key, - representations[key], - instances[i].name, - instances[i].version, - instances[i].metadata['ppro.clip.start'], - instances[i].metadata['ppro.clip.end'] - )); - - waitFile = request.stagingDir + '/' + instances[i].files[(instances[i].files.length - 1)]; - - } else if (key === 'thumbnail') { - instances[i].files.push(pype.exportThumbnail( - instances[i].name, - key, - instances[i].version, - request.stagingDir, - (instances[i].metadata['ppro.clip.start'] + ((instances[i].metadata["ppro.clip.end"] - instances[i].metadata['ppro.clip.start']) / 2)), - instances[i].metadata['ppro.timeline.fps'] - )); - } else if (key === 'projectfile') { - instances[i].files.push(instances[i].projectfile); - }; - } - } - request.waitingFor = waitFile; - // set back original in/out point on timeline - app.project.activeSequence.setInPoint(origInPoint); - app.project.activeSequence.setOutPoint(origOutPoint); - return JSON.stringify(request); - }, - - render: function (outputPath, family, representation, clipName, version, inPoint, outPoint) { - var outputPresetPath = $.getenv('EXTENSION_PATH').split('/').concat(['encoding', (representation.preset + '.epr')]).join($._PPP_.getSep()); - - app.enableQE(); - var activeSequence = qe.project.getActiveSequence(); // we use a QE DOM function, to determine the output extension. - if (activeSequence) { - app.encoder.launchEncoder(); // This can take a while; let's get the ball rolling. - - var projPath = new File(app.project.path); - - if ((outputPath) && projPath.exists) { - var outPreset = new File(outputPresetPath); - if (outPreset.exists === true) { - var outputFormatExtension = activeSequence.getExportFileExtension(outPreset.fsName); - if (outputFormatExtension) { - app.project.activeSequence.setInPoint(inPoint); - app.project.activeSequence.setOutPoint(outPoint); - var file = clipName + '_' + - family + - '_v' + version + - '.' + - outputFormatExtension; - var fullPathToFile = outputPath + - $._PPP_.getSep() + - file; - - var outFileTest = new File(fullPathToFile); - - if (outFileTest.exists) { - var destroyExisting = confirm("A file with that name already exists; overwrite?", false, "Are you sure...?"); - if (destroyExisting) { - outFileTest.remove(); - outFileTest.close(); - } - } - - app.encoder.bind('onEncoderJobComplete', $._PPP_.onEncoderJobComplete); - app.encoder.bind('onEncoderJobError', $._PPP_.onEncoderJobError); - app.encoder.bind('onEncoderJobProgress', $._PPP_.onEncoderJobProgress); - app.encoder.bind('onEncoderJobQueued', $._PPP_.onEncoderJobQueued); - app.encoder.bind('onEncoderJobCanceled', $._PPP_.onEncoderJobCanceled); - - - // use these 0 or 1 settings to disable some/all metadata creation. - app.encoder.setSidecarXMPEnabled(0); - app.encoder.setEmbeddedXMPEnabled(0); - - - var jobID = app.encoder.encodeSequence(app.project.activeSequence, - fullPathToFile, - outPreset.fsName, - app.encoder.ENCODE_IN_TO_OUT, - 1); // Remove from queue upon successful completion? - - $._PPP_.updateEventPanel('jobID = ' + jobID); - outPreset.close(); - return file; - } - } else { - $._PPP_.updateEventPanel("Could not find output preset."); - } - } else { - $._PPP_.updateEventPanel("Could not find/create output path."); - } - projPath.close(); - } else { - $._PPP_.updateEventPanel("No active sequence."); - } - }, - - log: function (info) { - app.setSDKEventMessage(JSON.stringify(info), 'info'); - }, - - message: function (msg) { - $.writeln(msg); // Using '$' object will invoke ExtendScript Toolkit, if installed. - }, - // $.getenv('PYTHONPATH') - alert_message: function (message) { - alert(message, "WARNING", true); - app.setSDKEventMessage(message, 'error'); - }, - getWorkFileVersion: function () { - var outputPath = pype.convertPathString(app.project.path); - var outputName = String(app.project.name); - var dirPath = outputPath.replace(outputName, ''); - var pattern = /_v([0-9]*)/g; - var search = pattern.exec(outputName); - var version = 1; - var newFileName, absPath; - - if (search) { - return search[1] - } else { - var create = confirm('The project file name is missing version `_v###` \n example: `NameOfFile_v001.prproj`\n\n Would you like to create version?', true, 'ERROR in name syntax'); - if (create) { - var splitName = outputName.split('.'); - newFileName = splitName[0] + '_v001.' + splitName[1]; - absPath = dirPath + newFileName; - app.project.saveAs(absPath.split('/').join($._PPP_.getSep())); - return '001'; - } - } - }, - saveProjectCopy: function (outputPath) { - var originalPath = pype.convertPathString(app.project.path); - var outputName = String(app.project.name); - - var fullOutPath = outputPath + $._PPP_.getSep() + outputName; - - app.project.saveAs(fullOutPath.split('/').join($._PPP_.getSep())); - - for (var a = 0; a < app.projects.numProjects; a++) { - var currentProject = app.projects[a]; - if (currentProject.path === fullOutPath) { - app.openDocument(originalPath); // Why first? So we don't frighten the user by making PPro's window disappear. :) - currentProject.closeDocument(); - } - } - }, - nextVersionCheck: function (dir, file, vCurVersStr, curVersStr, padding, nextVersNum) { - var replVers = vCurVersStr.replace(curVersStr, (nextVersNum).pad(padding)); - var newFileName = file.replace(vCurVersStr, replVers); - var absPath = dir + newFileName; - var absPathF = new File(absPath); - if (absPathF.exists) { - return pype.nextVersionCheck(dir, file, vCurVersStr, curVersStr, padding, (nextVersNum + 1)); - } else { - return absPathF - } - }, - versionUpWorkFile: function () { - var outputPath = pype.convertPathString(app.project.path); - var outputName = String(app.project.name); - var dirPath = outputPath.replace(outputName, ''); - var pattern = /_v([0-9]*)/g; - var search = pattern.exec(outputName); - var version = 1; - var newFileName, absPath; - - if (search) { - var match = parseInt(search[1], 10); - var padLength = search[1].length; - version += match; - var replVers = search[0].replace(search[1], (version).pad(padLength)); - newFileName = outputName.replace(search[0], replVers); - absPath = dirPath + newFileName; - - // check if new file already exists and offer confirmation - var absPathF = new File(absPath); - if (absPathF.exists) { - var overwrite = confirm('The file already exists! Do you want to overwrite it? NO: will save it as next available version', false, 'Are you sure...?'); - if (overwrite) { - // will overwrite - app.project.saveAs(absPath.split('/').join($._PPP_.getSep())); - return newFileName; - } else { - // will not overwrite - // will find next available version - absPathF = pype.nextVersionCheck(dirPath, outputName, search[0], search[1], padLength, (version + 1)); - absPath = pype.convertPathString(absPathF.fsName) - newFileName = absPath.replace(dirPath, '') - $.writeln('newFileName: ' + newFileName) - // will save it as new file - app.project.saveAs(absPath.split('/').join($._PPP_.getSep())); - return newFileName; - }; - } else { - app.project.saveAs(absPath.split('/').join($._PPP_.getSep())); - return newFileName; - }; - } else { - var create = confirm('The project file name is missing version `_v###` \n example: `NameOfFile_v001.prproj`\n\n Would you like to create version?", true, "ERROR in name syntax'); - if (create) { - var splitName = outputName.split('.'); - newFileName = splitName[0] + '_v001.' + splitName[1]; - absPath = dirPath + newFileName; - app.project.saveAs(absPath.split('/').join($._PPP_.getSep())); - return newFileName; - } - } - }, - transcodeExternal: function (fileToTranscode, fileOutputPath) { - fileToTranscode = typeof fileToTranscode !== 'undefined' ? fileToTranscode : 'C:\\Users\\hubert\\_PYPE_testing\\projects\\jakub_projectx\\resources\\footage\\raw\\day01\\bbt_test_001_raw.mov'; - fileOutputPath = typeof fileOutputPath !== 'undefined' ? fileOutputPath : 'C:\\Users\\hubert\\_PYPE_testing\\projects\\jakub_projectx\\editorial\\e01\\work\\edit\\transcode'; - - app.encoder.launchEncoder(); - var outputPresetPath = $.getenv('EXTENSION_PATH').split('/').concat(['encoding', 'prores422.epr']).join($._PPP_.getSep()); - var srcInPoint = 1.0; // encode start time at 1s (optional--if omitted, encode entire file) - var srcOutPoint = 3.0; // encode stop time at 3s (optional--if omitted, encode entire file) - var removeFromQueue = false; - - app.encoder.encodeFile( - fileToTranscode, - fileOutputPath, - outputPresetPath, - removeFromQueue, - srcInPoint, - srcOutPoint); - } -}; - -Number.prototype.pad = function (size) { - var s = String(this); - while (s.length < (size || 2)) { - s = "0" + s; - } - return s; -}; - -function include(arr, obj) { - for (var i = 0; i < arr.length; i++) { - if (arr[i] === obj) return true; - } - return false -} - -// var instances = pype.getPyblishRequest(); -// pype.encodeRepresentation(JSON.parse(instances)); diff --git a/pype/premiere/extensions/com.pype.avalon/mimetype b/pype/premiere/extensions/com.pype.avalon/mimetype deleted file mode 100644 index 96a3fe0900a..00000000000 --- a/pype/premiere/extensions/com.pype.avalon/mimetype +++ /dev/null @@ -1 +0,0 @@ -application/vnd.adobe.air-ucf-package+zip \ No newline at end of file diff --git a/pype/premiere/extensions/com.pype.avalon/ppro/css/avalon.min.css b/pype/premiere/extensions/com.pype.avalon/ppro/css/avalon.min.css deleted file mode 100644 index c0ac0d732b1..00000000000 --- a/pype/premiere/extensions/com.pype.avalon/ppro/css/avalon.min.css +++ /dev/null @@ -1,3 +0,0 @@ -body{background-color:#323238;color:#eeeeee}#output{background:#121212;color:#eeeeee;padding:2em;font-family:monospace;font-weight:bold;min-height:8em}.dark>.list-group-item{background:#454747} - -/*# sourceMappingURL=avalon.min.css.map */ \ No newline at end of file diff --git a/pype/premiere/extensions/com.pype.avalon/ppro/index.html b/pype/premiere/extensions/com.pype.avalon/ppro/index.html deleted file mode 100644 index 0d01e2f6128..00000000000 --- a/pype/premiere/extensions/com.pype.avalon/ppro/index.html +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - -Pype extention - - - - - - - - - - - - - - - - - - - - - - -
Refresh panel -
    -
  • -
    - -
    - Rename targeted text layers
    converts sc010sh020
    to lbb201sc010sh020
    and creates ftrack metadata
    -
    - -
    -
    - -
    -
    -
    - - -
    -
    -
  • -
  • -
    Publish
    -
    -
    - - -
    - - Version Up -
    - -
    - - Audio Only -
    - -
    -
    -
    - - -
    -
    -
    - -
    - - Path to sending data json -
    - -
    -
    -
    - - -
    -
    -
    - -
    - - Path to getting data json - -
    - -
    - -
    -
    - - -
    -
    - - -
    -
    - -
  • -
  • -
  • - -
  • -
    Load/Update assets to timeline
    -
    -
    - - Type -
    - -
    - Ext -
    - -
    -
    - -
    -
    -
  • -
- -
- -
- -
-
Output
-
- -
- - - - - - \ No newline at end of file diff --git a/pype/premiere/extensions/com.pype.avalon/ppro/js/avalon.js b/pype/premiere/extensions/com.pype.avalon/ppro/js/avalon.js deleted file mode 100644 index 6400c2f9640..00000000000 --- a/pype/premiere/extensions/com.pype.avalon/ppro/js/avalon.js +++ /dev/null @@ -1,367 +0,0 @@ -/* global CSInterface, $, querySelector, api, displayResult */ -var csi = new CSInterface(); -var output = document.getElementById('output'); - -var rootFolderPath = csi.getSystemPath(SystemPath.EXTENSION); -var timecodes = cep_node.require('node-timecodes'); -var process = cep_node.require('process'); - - -function getEnv() { - csi.evalScript('pype.getProjectFileData();', function (result) { - process.env.EXTENSION_PATH = rootFolderPath - window.ENV = process.env; - var resultData = JSON.parse(result); - for (key in resultData) { - window.ENV[key] = resultData[key]; - }; - csi.evalScript('pype.setEnvs(' + JSON.stringify(window.ENV) + ')'); - }); -} - -function renderClips() { - csi.evalScript('pype.transcodeExternal(' + rootFolderPath + ');', function (result) { - displayResult(result); - }); -} - -function displayResult(r) { - console.log(r); - csi.evalScript('$.writeln( ' + JSON.stringify(r) + ' )'); - output.classList.remove("error"); - output.innerText = r; -} - -function displayError(e) { - output.classList.add("error"); - output.innerText = e.message; -} - -function loadJSX() { - // get the appName of the currently used app. For Premiere Pro it's "PPRO" - var appName = csi.hostEnvironment.appName; - var extensionPath = csi.getSystemPath(SystemPath.EXTENSION); - - // load general JSX script independent of appName - var extensionRootGeneral = extensionPath + '/jsx/'; - csi.evalScript('$._ext.evalFiles("' + extensionRootGeneral + '")'); - - // load JSX scripts based on appName - var extensionRootApp = extensionPath + '/jsx/' + appName + '/'; - csi.evalScript('$._ext.evalFiles("' + extensionRootApp + '")'); - // csi.evalScript('$._PPP_.logConsoleOutput()'); - getEnv(); - - csi.evalScript('$._PPP_.updateEventPanel( "' + "all plugins are loaded" + '" )'); - csi.evalScript('$._PPP_.updateEventPanel( "' + "testing function done" + '" )'); - -} - -// run all at loading -loadJSX() - - -function loadAnimationRendersToTimeline() { - // it will get type of asset and extension from input - // and start loading script from jsx - var $ = querySelector('#load'); - var data = {}; - data.subset = $('input[name=type]').value; - data.subsetExt = $('input[name=ext]').value; - var requestList = []; - // get all selected clips - csi.evalScript('pype.getClipsForLoadingSubsets( "' + data.subset + '" )', function (result) { - // TODO: need to check if the clips are already created and this is just updating to last versions - var resultObj = JSON.parse(result); - var instances = resultObj[0]; - var numTracks = resultObj[1]; - - var key = ''; - // creating requesting list of dictionaries - for (key in instances) { - var clipData = {}; - clipData.parentClip = instances[key]; - clipData.asset = key; - clipData.subset = data.subset; - clipData.representation = data.subsetExt; - requestList.push(clipData); - } - // gets data from mongodb - api.load_representations(window.ENV['AVALON_PROJECT'], requestList).then( - function (avalonData) { - // creates or updates data on timeline - var makeData = {}; - makeData.binHierarchy = data.subset + '/' + data.subsetExt; - makeData.clips = avalonData; - makeData.numTracks = numTracks; - csi.evalScript('pype.importFiles( ' + JSON.stringify(makeData) + ' )'); - } - ); - }); -} - -function evalScript(script) { - var callback = function (result) { - displayResult(result); - }; - csi.evalScript(script, callback); -} - -function deregister() { - api.deregister_plugin_path().then(displayResult); -} - -function register() { - var $ = querySelector('#register'); - var path = $('input[name=path]').value; - api.register_plugin_path(path).then(displayResult); -} - -function getStagingDir() { - // create stagingDir - const fs = require('fs-extra'); - const os = require('os'); - const path = require('path'); - const UUID = require('pure-uuid'); - const id = new UUID(4).format(); - const stagingDir = path.join(os.tmpdir(), id); - - fs.mkdirs(stagingDir); - return stagingDir; - -} - -function convertPathString(path) { - return path.replace( - new RegExp('\\\\', 'g'), '/').replace(new RegExp('//\\?/', 'g'), ''); -} - -function publish() { - var $ = querySelector('#publish'); - // var gui = $('input[name=gui]').checked; - var gui = true; - var versionUp = $('input[name=version-up]').checked; - var audioOnly = $('input[name=audio-only]').checked; - var jsonSendPath = $('input[name=send-path]').value; - var jsonGetPath = $('input[name=get-path]').value; - var publish_path = window.ENV['PUBLISH_PATH']; - - if (jsonSendPath == '') { - // create temp staging directory on local - var stagingDir = convertPathString(getStagingDir()); - - // copy project file to stagingDir - const fs = require('fs-extra'); - const path = require('path'); - - csi.evalScript('pype.getProjectFileData();', function (result) { - displayResult(result); - var data = JSON.parse(result); - displayResult(stagingDir); - displayResult(data.projectfile); - var destination = convertPathString(path.join(stagingDir, data.projectfile)); - displayResult('copy project file'); - displayResult(data.projectfile); - displayResult(destination); - fs.copyFile(data.projectpath, destination); - displayResult('project file coppied!'); - }); - - // publishing file - csi.evalScript('pype.getPyblishRequest("' + stagingDir + '", ' + audioOnly + ');', function (r) { - var request = JSON.parse(r); - displayResult(JSON.stringify(request)); - - csi.evalScript('pype.encodeRepresentation(' + JSON.stringify(request) + ');', function (result) { - // create json for pyblish - var jsonfile = require('jsonfile'); - var jsonSendPath = stagingDir + '_send.json' - var jsonGetPath = stagingDir + '_get.json' - $('input[name=send-path]').value = jsonSendPath; - $('input[name=get-path]').value = jsonGetPath; - var jsonContent = JSON.parse(result); - jsonfile.writeFile(jsonSendPath, jsonContent); - var checkingFile = function (path) { - var timeout = 1000; - setTimeout(function () { - if (fs.existsSync(path)) { - // register publish path - api.register_plugin_path(publish_path).then(displayResult); - // send json to pyblish - api.publish(jsonSendPath, jsonGetPath, gui).then(function (result) { - // check if resulted path exists as file - if (fs.existsSync(result.get_json_path)) { - // read json data from resulted path - displayResult('Updating metadata of clips after publishing'); - - jsonfile.readFile(result.get_json_path, function (err, json) { - csi.evalScript('pype.dumpPublishedInstancesToMetadata(' + JSON.stringify(json) + ');'); - }) - - // version up project - if (versionUp) { - displayResult('Saving new version of the project file'); - csi.evalScript('pype.versionUpWorkFile();'); - }; - } else { - // if resulted path file not existing - displayResult('Publish has not been finished correctly. Hit Publish again to publish from already rendered data, or Reset to render all again.'); - }; - - }); - - } else { - displayResult('waiting'); - checkingFile(path); - }; - }, - timeout) - }; - - checkingFile(jsonContent.waitingFor) - }); - }); - } else { - // register publish path - api.register_plugin_path(publish_path).then(displayResult); - // send json to pyblish - api.publish(jsonSendPath, jsonGetPath, gui).then(function (result) { - // check if resulted path exists as file - if (fs.existsSync(result.get_json_path)) { - // read json data from resulted path - displayResult('Updating metadata of clips after publishing'); - - jsonfile.readFile(result.get_json_path, function (err, json) { - csi.evalScript('pype.dumpPublishedInstancesToMetadata(' + JSON.stringify(json) + ');'); - }) - - // version up project - if (versionUp) { - displayResult('Saving new version of the project file'); - csi.evalScript('pype.versionUpWorkFile();'); - }; - } else { - // if resulted path file not existing - displayResult('Publish has not been finished correctly. Hit Publish again to publish from already rendered data, or Reset to render all again.'); - }; - - }); - }; - // $('input[name=send-path]').value = ''; - // $('input[name=get-path]').value = ''; -} - -function context() { - var $ = querySelector('#context'); - var project = $('input[name=project]').value; - var asset = $('input[name=asset]').value; - var task = $('input[name=task]').value; - var app = $('input[name=app]').value; - api.context(project, asset, task, app).then(displayResult); -} - -function tc(timecode) { - var seconds = timecodes.toSeconds(timecode); - var timec = timecodes.fromSeconds(seconds); - displayResult(seconds); - displayResult(timec); -} - -function rename() { - var $ = querySelector('#rename'); - var data = {}; - data.ep = $('input[name=episode]').value; - data.epSuffix = $('input[name=ep_suffix]').value; - - if (!data.ep) { - csi.evalScript('pype.alert_message("' + 'Need to fill episode code' + '")'); - return; - }; - - if (!data.epSuffix) { - csi.evalScript('pype.alert_message("' + 'Need to fill episode longer suffix' + '")'); - return; - }; - - csi.evalScript('br.renameTargetedTextLayer( ' + JSON.stringify(data) + ' );', function (result) { - displayResult(result); - }); -} - -// bind buttons -$('#btn-getRernderAnimation').click(function () { - loadAnimationRendersToTimeline(); -}); - -$('#btn-rename').click(function () { - rename(); -}); - -$('#btn-set-context').click(function () { - context(); -}); - -$('#btn-register').click(function () { - register(); -}); - -$('#btn-deregister').click(function () { - deregister(); -}); - -$('#btn-publish').click(function () { - publish(); -}); - -$('#btn-send-reset').click(function () { - var $ = querySelector('#publish'); - $('input[name=send-path]').value = ''; -}); -$('#btn-get-reset').click(function () { - var $ = querySelector('#publish'); - $('input[name=get-path]').value = ''; -}); -$('#btn-get-active-sequence').click(function () { - evalScript('pype.getActiveSequence();'); -}); - -$('#btn-get-selected').click(function () { - $('#output').html('getting selected clips info ...'); - evalScript('pype.getSelectedItems();'); -}); - -$('#btn-get-env').click(function () { - displayResult(window.ENV); -}); - -$('#btn-get-projectitems').click(function () { - evalScript('pype.getProjectItems();'); -}); - -$('#btn-metadata').click(function () { - var $ = querySelector('#publish'); - var path = $('input[name=get-path]').value; - var jsonfile = require('jsonfile'); - displayResult(path); - jsonfile.readFile(path, function (err, json) { - csi.evalScript('pype.dumpPublishedInstancesToMetadata(' + JSON.stringify(json) + ');'); - displayResult('Metadata of clips after publishing were updated'); - }) - - -}); -$('#btn-get-frame').click(function () { - evalScript('$._PPP_.exportCurrentFrameAsPNG();'); -}); - -$('#btn-tc').click(function () { - tc('00:23:47:10'); -}); - -$('#btn-generateRequest').click(function () { - evalScript('pype.getPyblishRequest();'); -}); - -$('#btn-newWorkfileVersion').click(function () { - evalScript('pype.versionUpWorkFile();'); -}); diff --git a/pype/premiere/extensions/com.pype.avalon/ppro/js/pico_client.js b/pype/premiere/extensions/com.pype.avalon/ppro/js/pico_client.js deleted file mode 100644 index fdb8e31a189..00000000000 --- a/pype/premiere/extensions/com.pype.avalon/ppro/js/pico_client.js +++ /dev/null @@ -1,75 +0,0 @@ -// pico connection of python module name -var api = pico.importModule('api'); - -function querySelector(parent) { - return function (child) { - return document.querySelector(parent).querySelector(child) - }; -} - -var defs = {} - -function jumpTo(name) { - var e = defs[name]; - document.querySelectorAll('.highlight').forEach(function (el) { - el.classList.remove('highlight'); - }); - e.classList.add('highlight'); - return false; -} - -function unindent(code) { - var lines = code.split('\n'); - var margin = -1; - for (var j = 0; j < lines.length; j++) { - var l = lines[j]; - for (i = 0; i < l.length; i++) { - if (l[i] != " ") { - margin = i; - break; - } - } - if (margin > -1) { - break; - } - } - lines = lines.slice(j); - return lines.map(function (s) { - return s.substr(margin) - }).join('\n'); -} - - -function ready() { - // // set the element of each example to the corresponding functions source - // document.querySelectorAll('li pre code.js').forEach(function(e){ - // var id = e.parentElement.parentElement.id; - // var f = window[id]; - // var code = f.toString().split('\n').slice(2, -1).join('\n'); - // e.innerText = unindent(code); - // }) - - document.querySelectorAll('li pre code.html').forEach(function (e) { - var html = e.parentElement.parentElement.querySelector('div.example').innerHTML; - e.innerText = unindent(html); - }) - - hljs.initHighlighting(); - - // // find all the elements representing the function definitions in the python source - // document.querySelectorAll('.python .hljs-function .hljs-title').forEach(function(e){ - // var a = document.createElement('a'); - // a.name = e.innerText; - // e.parentElement.insertBefore(a, e) - // return defs[e.innerText] = e.parentElement; - // }); - - // convert all 'api.X' strings to hyperlinks to jump to python source - document.querySelectorAll('.js').forEach(function (e) { - var code = e.innerHTML; - Object.keys(defs).forEach(function (k) { - code = code.replace('api.' + k + '(', 'api.' + k + '('); - }) - e.innerHTML = code; - }) -} diff --git a/pype/premiere/extensions/com.pype.avalon/pypeAvalon.jsx b/pype/premiere/extensions/com.pype.avalon/pypeAvalon.jsx deleted file mode 100644 index d459d0f3e24..00000000000 --- a/pype/premiere/extensions/com.pype.avalon/pypeAvalon.jsx +++ /dev/null @@ -1,92 +0,0 @@ -/************************************************************************* - * ADOBE CONFIDENTIAL - * ___________________ - * - * Copyright 2014 Adobe - * All Rights Reserved. - * - * NOTICE: Adobe permits you to use, modify, and distribute this file in - * accordance with the terms of the Adobe license agreement accompanying - * it. If you have received this file from a source other than Adobe, - * then your use, modification, or distribution of it requires the prior - * written permission of Adobe. - **************************************************************************/ -var json2 = '~/AppData/Roaming/Adobe/CEP/extensions/com.pype.avalon/js/json2.js'; -$.evalFile(json2); - - -if (typeof ($) == 'undefined') { - $ = {}; -} - -if (typeof (pype) == 'undefined') { - var pype = {}; -} - -if (typeof (br) == 'undefined') { - var br = {}; -} - -function keepExtention() { - return app.setExtensionPersistent("com.pype.avalon", 0); -} - -keepExtention() - -$._ext = { - // Evaluate a file and catch the exception. - evalFile: function (path) { - try { - $.evalFile(path); - $.writeln(path); - } catch (e) { - $.writeln(e); - alert("Exception:" + e); - } - }, - // Evaluate all the files in the given folder - evalFiles: function (jsxFolderPath) { - var folder = new Folder(jsxFolderPath); - if (folder.exists) { - var jsxFiles = folder.getFiles("*.jsx"); - for (var i = 0; i < jsxFiles.length; i++) { - var jsxFile = jsxFiles[i]; - $._ext.evalFile(jsxFile); - } - } - }, - // entry-point function to call scripts more easily & reliably - callScript: function (dataStr) { - try { - var dataObj = JSON.parse(decodeURIComponent(dataStr)); - if ( - !dataObj || - !dataObj.namespace || - !dataObj.scriptName || - !dataObj.args - ) { - throw new Error('Did not provide all needed info to callScript!'); - } - // call the specified jsx-function - var result = $[dataObj.namespace][dataObj.scriptName].apply( - null, - dataObj.args - ); - // build the payload-object to return - var payload = { - err: 0, - result: result - }; - return encodeURIComponent(JSON.stringify(payload)); - } catch (err) { - payload = { - err: err - }; - return encodeURIComponent(JSON.stringify(payload)); - } - } -}; - -// var dalsiJsxFile = 'C:\\Users\\hubert\\CODE\\pype-setup\\repos\\pype-config\\pype\\premiere\\extensions\\com.pype.avalon\\jsx\\pype.jsx'; -// // $._ext.evalFile(dalsiJsxFile); -// $.evalFile(dalsiJsxFile); diff --git a/pype/premiere/extensions/com.pype/.debug b/pype/premiere/extensions/com.pype/.debug new file mode 100644 index 00000000000..3043fa86c67 --- /dev/null +++ b/pype/premiere/extensions/com.pype/.debug @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/pype/premiere/extensions/com.pype.avalon/CSXS/manifest.xml b/pype/premiere/extensions/com.pype/CSXS/manifest.xml similarity index 83% rename from pype/premiere/extensions/com.pype.avalon/CSXS/manifest.xml rename to pype/premiere/extensions/com.pype/CSXS/manifest.xml index 259f49fd827..2e3313676fd 100644 --- a/pype/premiere/extensions/com.pype.avalon/CSXS/manifest.xml +++ b/pype/premiere/extensions/com.pype/CSXS/manifest.xml @@ -2,9 +2,9 @@ - + - + @@ -19,11 +19,11 @@ accordance with the terms of the Adobe license agreement accompanying * it. If y - + ./index_remote.html - ./pypeAvalon.jsx + ./pypeApp.jsx --enable-nodejs --mixed-context @@ -35,7 +35,7 @@ accordance with the terms of the Adobe license agreement accompanying * it. If y Panel - Avalon + Pype 600 diff --git a/pype/premiere/extensions/com.pype.avalon/encoding/44khz.epr b/pype/premiere/extensions/com.pype/encoding/44khz.epr similarity index 100% rename from pype/premiere/extensions/com.pype.avalon/encoding/44khz.epr rename to pype/premiere/extensions/com.pype/encoding/44khz.epr diff --git a/pype/premiere/extensions/com.pype.avalon/encoding/48khz.epr b/pype/premiere/extensions/com.pype/encoding/48khz.epr similarity index 100% rename from pype/premiere/extensions/com.pype.avalon/encoding/48khz.epr rename to pype/premiere/extensions/com.pype/encoding/48khz.epr diff --git a/pype/premiere/extensions/com.pype.avalon/encoding/h264.epr b/pype/premiere/extensions/com.pype/encoding/h264.epr similarity index 100% rename from pype/premiere/extensions/com.pype.avalon/encoding/h264.epr rename to pype/premiere/extensions/com.pype/encoding/h264.epr diff --git a/pype/premiere/extensions/com.pype/encoding/jpeg_thumb.epr b/pype/premiere/extensions/com.pype/encoding/jpeg_thumb.epr new file mode 100644 index 00000000000..b1ad79df16c --- /dev/null +++ b/pype/premiere/extensions/com.pype/encoding/jpeg_thumb.epr @@ -0,0 +1,5470 @@ + + + + + false + + false + + + + false + -1 + + false + false + + 10 + + 0 + false + -101606400000000000 + false + false + true + false + 0 + 0,0,0,0 + false + 0 + + + false + true + false + 2a690bef-07f2-46ff-8f4d-0110b28a7ab5 + + + 1246774599 + 1061109567 + + + + + Custom + jpeg_thumb + + 1 + + + + + + 0 + 0 + + + + + 0 + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 10 + 0 + + + 1 + + + + + + + + + + ADBEVideoTabGroup + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 8 + 0 + + + 1 + + + + + + + + + ADBEBasicVideoGroup + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 8 + 0 + + + 1 + + + + + + + + + + + + + + + + + fwAAAA== + ADBEVideoMatchSource + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 7 + false + + + + + ADBEVideoQuality + false + false + false + false + false + false + false + false + false + false + false + true + 0 + false + 1 + 2 + 100 + + + + + ADBEVideoWidth + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 2 + 2 + 1920 + + + + + ADBEVideoHeight + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 3 + 2 + 1080 + + + + + ADBEStillSequence + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 4 + 1 + true + + + + + ADBEVideoFPS + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 5 + 4 + 8475667200 + + + + + ADBEVideoFieldType + false + false + false + false + false + false + false + false + true + false + false + false + 0 + false + 6 + 2 + 2 + + + + + ADBEVideoAspect + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 7 + 11 + 10,11 + + + + + ADBERenderDeepColor + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 8 + 1 + true + + + + + ADBEExportColorSpace + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 9 + 2 + 0 + + + + + + PostEncodeHostMultiGroup + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 1 + 8 + 0 + + + 1 + + + + + + + + + + + + + + + + ADBECCGroup + false + false + false + false + false + false + false + false + false + true + false + false + 0 + false + 0 + 8 + 0 + + + 1 + + + + + + + + + ADBECCFileSyncFolder + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 2 + 0 + + + + + ADBECCFileSyncSubFolder + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 1 + 6 + + + + + + + ADBEStockGroup + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 1 + 8 + 0 + + + 1 + + + + + + + + + + ADBEStockLoginSubGroup + false + false + false + false + false + false + false + false + false + true + false + false + 0 + false + 0 + 8 + 0 + + + 1 + + + + + + + + + ADBEStockStatusText + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 2 + 0 + + + + + ADBEStockLogin + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 1 + 7 + false + + + + + ADBEStockRefreshToken + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 1 + 9 + + + + + + ADBEBehanceGroup + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 2 + 8 + 0 + + + 1 + + + + + + + + + + + + + ADBEBehanceLoginSubGroup + false + false + false + false + false + false + false + false + false + true + false + false + 0 + false + 0 + 8 + 0 + + + 1 + + + + + + + + + ADBEBehanceStatusText + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 2 + 0 + + + + + ADBEBehanceLogin + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 1 + 7 + false + + + + + ADBEBehanceDescription + false + false + false + false + false + false + true + false + false + false + false + false + 8 + false + 1 + 6 + + + + + + ADBEBehanceTags + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 2 + 6 + + + + + + ADBEBehanceDeleteLocalFile + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 3 + 1 + false + + + + + ADBEBehanceRefreshToken + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 4 + 9 + + + + + + ADBEFacebookGroup + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 3 + 8 + 0 + + + 1 + + + + + + + + + + + + + + + + + ADBEFacebookLoginSubGroup + false + false + false + false + false + false + false + false + false + true + false + false + 0 + false + 0 + 8 + 0 + + + 1 + + + + + + + + + ADBEFacebookStatusText + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 2 + 0 + + + + + ADBEFacebookLogin + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 1 + 7 + false + + + + + ADBEFacebookPages + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 1 + 2 + 0 + + + + + ADBEFacebookTitle + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 2 + 6 + + + + + + ADBEFacebookPost + false + false + false + false + false + false + true + false + false + false + false + false + 8 + false + 3 + 6 + + + + + + ADBEFacebookDeleteLocalFile + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 4 + 1 + false + + + + + ADBEFacebookRefreshToken + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 5 + 9 + + + + + ADBEFacebookAccountToken + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 6 + 9 + + + + + ADBEFacebookPagesToken + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 7 + 6 + + + + + + ADBEFacebookDescription + false + false + false + false + false + false + true + false + false + false + false + false + 0 + false + 8 + 6 + + + + + + + ADBEFTPGroup + false + false + false + false + false + false + false + false + false + true + false + false + 0 + false + 4 + 8 + 0 + + + 1 + + + + + + + + + + + + + + + + ADBEFTPUserID + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 6 + + + + + + ADBEFTPPassword + false + false + false + false + false + true + false + false + false + false + false + false + 0 + false + 1 + 6 + + + + + + ADBEFTPServerAddress + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 2 + 6 + + + + + + ADBEFTPPort + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 3 + 2 + 21 + + + + + ADBEFTPRemotePath + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 4 + 6 + + + + + + ADBEFTPRetries + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 5 + 2 + 1 + + + + + ADBEFTPDeleteLocalFileAfterTransfer + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 6 + 1 + false + + + + + ADBEFTPTest + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 7 + 7 + false + + + + + ADBEFTPVerifyUpload + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 8 + 1 + true + + + + + + ADBETwitterGroup + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 5 + 8 + 0 + + + 1 + + + + + + + + + + + + ADBETwitterLoginSubGroup + false + false + false + false + false + false + false + false + false + true + false + false + 0 + false + 0 + 8 + 0 + + + 1 + + + + + + + + + ADBETwitterStatusText + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 2 + 0 + + + + + ADBETwitterLogin + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 1 + 7 + false + + + + + ADBETwitterDescription + false + false + false + false + false + false + true + false + false + false + false + false + 8 + false + 1 + 6 + + + + + + ADBETwitterDeleteLocalFile + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 2 + 1 + false + + + + + ADBETwitterRefreshToken + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 3 + 9 + + + + + + ADBEVimeoGroup + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 6 + 8 + 0 + + + 1 + + + + + + + + + + + + + + + + + + + + ADBEVimeoLoginSubGroup + false + false + false + false + false + false + false + false + false + true + false + false + 0 + false + 0 + 8 + 0 + + + 1 + + + + + + + + + ADBEVimeoStatusText + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 2 + 0 + + + + + ADBEVimeoLogin + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 1 + 7 + false + + + + + ADBEVimeoChannel + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 1 + 2 + 0 + + + + + ADBEVimeoTitle + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 2 + 6 + + + + + + ADBEVimeoDescription + false + false + false + false + false + false + true + false + false + false + false + false + 0 + false + 3 + 6 + + + + + + ADBEVimeoPrivacy + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 4 + 2 + 0 + + + + + ADBEVimeoPassword + false + false + false + false + false + true + false + false + true + false + false + false + 0 + false + 5 + 6 + + + + + + ADBEVimeoTags + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 6 + 6 + + + + + + ADBEVimeoDeleteLocalFile + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 7 + 1 + false + + + + + ADBEVimeoRefreshToken + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 8 + 9 + + + + + ADBEVimeoChannelToken + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 9 + 6 + + + + + + ADBEVimeoPasswordToken + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 10 + 9 + + + + + ADBEVimeoAuthorizationToken + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 11 + 6 + + + + + + + ADBEYouTubeGroup + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 7 + 8 + 0 + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + ADBEYouTubeLoginSubGroup + false + false + false + false + false + false + false + false + false + true + false + false + 0 + false + 0 + 8 + 0 + + + 1 + + + + + + + + + ADBEYouTubeStatusText + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 2 + 0 + + + + + ADBEYouTubeLogin + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 1 + 7 + false + + + + + + ADBEYouTubeChannelPlaylistGroup + false + false + false + false + true + false + false + false + false + false + false + false + 0 + false + 1 + 8 + 0 + + + 1 + + + + + + + + + + ADBEYouTubeChannel + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 2 + 2 + + + + + ADBEYouTubeChannelAdd + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 1 + 7 + false + + + + + ADBEYouTubeChannelRemove + false + false + false + false + false + false + false + false + false + true + false + false + 0 + false + 2 + 7 + false + + + + + ADBEYouTubePlaylist + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 2 + 2 + 2 + + + + + ADBEYouTubeTitle + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 3 + 6 + + + + + + ADBEYouTubeDescription + false + false + false + false + false + false + true + false + false + false + false + false + 0 + false + 4 + 6 + + + + + + ADBEYouTubePrivacy + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 5 + 2 + 2 + + + + + ADBEYouTubeTags + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 6 + 6 + + + + + + ADBEYouTubeRefreshToken + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 7 + 6 + + + + + + ADBEYouTubeChannelToken + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 8 + 9 + + + + + ADBEYouTubePlaylistToken + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 9 + 9 + + + + + ADBEYouTubeThumbnailUse + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 10 + 2 + 0 + + + + + + ADBEYouTubeThumbnailSubGroup + false + false + false + false + true + false + false + false + false + false + false + false + 0 + false + 11 + 8 + 0 + + + 1 + + + + + + + + + ADBEYouTubeThumbnailTime + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 4 + 0 + + + + + ADBEYouTubeThumbnailTimeBtn + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 1 + 7 + false + + + + + ADBEYouTubeThumbnailTimeToken + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 12 + 5 + 0 + + + + + ADBEYouTubeThumbnailFile + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 13 + 2 + 0 + + + + + ADBEYouTubeThumbnailFileToken + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 14 + 9 + + + + + ADBEYouTubeDeleteLocalFile + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 15 + 1 + false + + + + + ADBEYouTubeThumbnailPoster + false + false + false + false + false + false + false + true + true + false + false + false + 128 + false + 16 + 12 + 0 + + + + + ADBEYouTubeCategory + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 17 + 2 + 0 + + + 9 + + + + + + + + + + + + + 0 + 1 + false + + + + + + 0 + 1. + 0 + 0 + 228cda18-3625-4d2d-951e-348879e4ed93 + 1 + + AE.ADBE Lumetri + InternalSerialize + + + 2 + AE.ADBE Lumetri + + + + 0 + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Lumetri Color + false + 0 + + + + + + 1 + + 0 + /v4= + -91445760000000000 + 10 + false + false + false + Blob + + + + + 62 + false + + true + false + false + -91445760000000000,false,0,0,0,0,0,0 + 4 + false + false + false + + + + + + + 2 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 11 + false + false + false + + Basic Correction + + + + + 3 + false + + true + false + false + -91445760000000000,true,0,0,0,0,0,0 + 4 + false + false + false + + + + + + + 4 + + 0 + /v4= + -91445760000000000 + 10 + false + false + false + + + + + + 95 + + 0 + /v4= + -91445760000000000 + 10 + false + false + false + + + + + + 5 + false + + 998 + 0 + 0 + -91445760000000000,0,0,0,0,0,0,0 + 7 + true + false + false + + Input LUT + + + + + 63 + false + + 1000. + 100. + 0. + -91445760000000000,100.,0,0,0,0,0,0 + 8 + false + false + false + + HDR White + + + + + 6 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 11 + false + false + false + + White Balance + + + + + 94 + false + + 18446744073709551615 + 0 + 0 + -91445760000000000,18374897589125431296,0,0,0,0,0,0 + 5 + false + false + false + + WB Selector + + + + + 7 + false + + 100. + -100. + 300. + -300. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Temperature + + + + + 8 + false + + 100. + -100. + 300. + -300. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Tint + + + + + 9 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 12 + false + false + false + + + + + + + 10 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 11 + false + false + false + + Tone + + + + + 11 + false + + 5. + -5. + 7. + -7. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Exposure + + + + + 12 + false + + 100. + -100. + 150. + -150. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Contrast + + + + + 13 + false + + 100. + -100. + 150. + -150. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Highlights + + + + + 14 + false + + 100. + -100. + 150. + -150. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Shadows + + + + + 15 + false + + 100. + -100. + 150. + -150. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Whites + + + + + 16 + false + + 100. + -100. + 150. + -150. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Blacks + + + + + 64 + false + + 100. + -100. + 150. + -150. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + HDR Specular + + + + + 17 + false + + true + false + false + -91445760000000000,false,0,0,0,0,0,0 + 16 + false + false + false + + + + + + + 18 + false + + true + false + false + -91445760000000000,false,0,0,0,0,0,0 + 16 + false + false + false + + + + + + + 19 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 12 + false + false + false + + + + + + + 20 + false + + 200. + 300. + 0. + 0. + -91445760000000000,100.,0,0,0,0,0,0 + 8 + false + false + false + + Saturation + + + + + 21 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 12 + false + false + false + + + + + + + 22 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 11 + false + false + false + + Creative + + + + + 23 + false + + true + false + false + -91445760000000000,true,0,0,0,0,0,0 + 4 + false + false + false + + + + + + + 24 + + 0 + /v4= + -91445760000000000 + 10 + false + false + false + + + + + + 96 + + 0 + /v4= + -91445760000000000 + 10 + false + false + false + + + + + + 25 + false + + 998 + 0 + 0 + -91445760000000000,0,0,0,0,0,0,0 + 7 + true + false + false + + Look + + + + + 26 + false + + 200. + 0. + 0. + -91445760000000000,100.,0,0,0,0,0,0 + 8 + false + false + false + + Intensity + + + + + 27 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 11 + false + false + false + + Adjustments + + + + + 28 + false + + 100. + 150. + 0. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Faded Film + + + + + 29 + false + + 100. + -100. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Sharpen + + + + + 30 + false + + 100. + -100. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Vibrance + + + + + 31 + false + + 200. + 300. + 0. + 0. + -91445760000000000,100.,0,0,0,0,0,0 + 8 + false + false + false + + Saturation + + + + + 32 + + 0 + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + -91445760000000000 + 9 + false + false + false + + + + + + 33 + false + + 100. + -100. + 150. + -150. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Tint Balance + + + + + 34 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 12 + false + false + false + + + + + + + 35 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 12 + false + false + false + + + + + + + 36 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 11 + false + false + false + + Curves + + + + + 37 + false + + true + false + false + -91445760000000000,true,0,0,0,0,0,0 + 4 + false + false + false + + + + + + + 38 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 11 + false + false + false + + RGB Curves + + + + + 118 + false + + true + false + false + -91445760000000000,true,0,0,0,0,0,0 + 4 + false + false + false + + + + + + + 65 + false + + 10000. + 100. + 0. + -91445760000000000,100.,0,0,0,0,0,0 + 8 + false + false + false + + HDR Range + + + + + 39 + + 0 + AAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8D8AAAAAAADwPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA/AAAAAAAA8D8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwPwAAAAAAAPA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8D8AAAAAAADwPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + -91445760000000000 + 9 + false + false + false + + + + + + 40 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 12 + false + false + false + + + + + + + 41 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 11 + false + false + false + + Hue Saturation Curves + + + + + 104 + false + + true + false + false + -91445760000000000,true,0,0,0,0,0,0 + 4 + false + false + false + + + + + + + 113 + false + + 18446744073709551615 + 0 + 0 + -91445760000000000,18374686479671623936,0,0,0,0,0,0 + 5 + false + false + false + + Hue (vs Sat) Selector + + + + + 42 + + 0 + AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8D8AAAAAAADwPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + -91445760000000000 + 9 + false + false + false + Hue vs Sat + + + + + 105 + false + + true + false + false + -91445760000000000,true,0,0,0,0,0,0 + 4 + false + false + false + + + + + + + 114 + false + + 18446744073709551615 + 0 + 0 + -91445760000000000,18374686479671623936,0,0,0,0,0,0 + 5 + false + false + false + + Hue (vs Hue) Selector + + + + + 106 + + 0 + AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8D8AAAAAAADwPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + -91445760000000000 + 9 + false + false + false + Hue vs Hue + + + + + 107 + false + + true + false + false + -91445760000000000,true,0,0,0,0,0,0 + 4 + false + false + false + + + + + + + 115 + false + + 18446744073709551615 + 0 + 0 + -91445760000000000,18374686479671623936,0,0,0,0,0,0 + 5 + false + false + false + + Hue (vs Luma) Selector + + + + + 108 + + 0 + AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8D8AAAAAAADwPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + -91445760000000000 + 9 + false + false + false + Hue vs Luma + + + + + 109 + false + + true + false + false + -91445760000000000,true,0,0,0,0,0,0 + 4 + false + false + false + + + + + + + 116 + false + + 18446744073709551615 + 0 + 0 + -91445760000000000,18374686479671623936,0,0,0,0,0,0 + 5 + false + false + false + + Luma (vs Sat) Selector + + + + + 110 + + 0 + AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8D8AAAAAAADwPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + -91445760000000000 + 9 + false + false + false + Luma vs Sat + + + + + 111 + false + + true + false + false + -91445760000000000,true,0,0,0,0,0,0 + 4 + false + false + false + + + + + + + 117 + false + + 18446744073709551615 + 0 + 0 + -91445760000000000,18374686479671623936,0,0,0,0,0,0 + 5 + false + false + false + + Sat (vs Sat) Selector + + + + + 112 + + 0 + AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8D8AAAAAAADwPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + -91445760000000000 + 9 + false + false + false + Sat vs Sat + + + + + 43 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 12 + false + false + false + + + + + + + 44 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 12 + false + false + false + + + + + + + 45 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 11 + false + false + false + + Color Wheels & Match + + + + + 46 + false + + true + false + false + -91445760000000000,true,0,0,0,0,0,0 + 4 + false + false + false + + + + + + + 101 + false + + true + false + false + -91445760000000000,false,0,0,0,0,0,0 + 10 + false + false + false + + + + + + + 102 + false + + true + false + false + -91445760000000000,true,0,0,0,0,0,0 + 10 + false + false + false + + + + + + + 103 + false + + true + false + false + -91445760000000000,false,0,0,0,0,0,0 + 10 + false + false + false + + + + + + + 66 + false + + 1000. + 100. + 0. + -91445760000000000,100.,0,0,0,0,0,0 + 8 + false + false + false + + HDR White + + + + + 47 + + 0 + AAAAAAAAAAAAAAAAAADgPwAAAAAAAAAAAAAAAAAAAAAAAAAAAADgPwAAAAAAAAAAAAAAAAAAAAAAAAAAAADgPwAAAAAAAAAAAAAAAAAAAAAAAAAAAADgPwAAAAAAAAAA + -91445760000000000 + 9 + false + false + false + + + + + + 48 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 12 + false + false + false + + + + + + + 67 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 11 + false + false + false + + HSL Secondary + + + + + 68 + false + + true + false + false + -91445760000000000,true,0,0,0,0,0,0 + 4 + false + false + false + + + + + + + 69 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 11 + false + false + false + + Key + + + + + 70 + false + + 18446744073709551615 + 0 + 0 + -91445760000000000,18374686479671623680,0,0,0,0,0,0 + 5 + false + false + false + + Set color + + + + + 71 + false + + 18446744073709551615 + 0 + 0 + -91445760000000000,18374686479671623680,0,0,0,0,0,0 + 5 + false + false + false + + Add color + + + + + 72 + false + + 18446744073709551615 + 0 + 0 + -91445760000000000,18374686479671623680,0,0,0,0,0,0 + 5 + false + false + false + + Remove color + + + + + 73 + + 0 + AAAAAD8AAAAAAAAAAAEAAAA/AAAAAAAAAAABAAAAPwAAAAAAAAAAAQ== + -91445760000000000 + 9 + false + false + false + + + + + + 74 + false + + true + false + false + -91445760000000000,false,0,0,0,0,0,0 + 4 + false + false + false + + + + + + + 75 + false + + 2 + 0 + 0 + -91445760000000000,0,0,0,0,0,0,0 + 7 + true + false + false + + + + + + + 76 + false + + true + false + false + -91445760000000000,false,0,0,0,0,0,0 + 4 + false + false + false + + + + + + + 77 + false + + true + false + false + -91445760000000000,false,0,0,0,0,0,0 + 16 + false + false + false + + + + + + + 78 + false + + true + false + false + -91445760000000000,false,0,0,0,0,0,0 + 16 + false + false + false + + + + + + + 79 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 12 + false + false + false + + + + + + + 80 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 11 + false + false + false + + Refine + + + + + 81 + false + + 100. + 0. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Denoise + + + + + 82 + false + + 30. + 1000. + 0. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Blur + + + + + 83 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 12 + false + false + false + + Blur + + + + + 84 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 11 + false + false + false + + Correction + + + + + 85 + + 0 + AAAAAAAAAAAAAAAAAADgPwAAAAAAAAAAAAAAAAAAAAAAAAAAAADgPwAAAAAAAAAAAAAAAAAAAAAAAAAAAADgPwAAAAAAAAAAAAAAAAAAAAAAAAAAAADgPwAAAAAAAAAAAAAAAAAAAAAAAAAAAADgPwAAAAAAAAAAAAAAAAAAAAAAAAAAAADgPwAAAAAAAAAAAAAAAAAAAAAAAAAAAADgPwAAAAAAAAAAAAAAAAAAAAAAAAAAAADgPwAAAAAAAAAA + -91445760000000000 + 9 + false + false + false + + + + + + 93 + + 0 + AAAAAA== + -91445760000000000 + 10 + false + false + false + + + + + + 86 + false + + 100. + -100. + 300. + -300. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Temperature + + + + + 87 + false + + 100. + -100. + 300. + -300. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Tint + + + + + 88 + false + + 100. + -100. + 150. + -150. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Contrast + + + + + 89 + false + + 100. + -100. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Sharpen + + + + + 90 + false + + 200. + 300. + 0. + 0. + -91445760000000000,100.,0,0,0,0,0,0 + 8 + false + false + false + + Saturation + + + + + 91 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 12 + false + false + false + + Saturation + + + + + 92 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 12 + false + false + false + + + + + + + 49 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 11 + false + false + false + + Vignette + + + + + 50 + false + + true + false + false + -91445760000000000,true,0,0,0,0,0,0 + 4 + false + false + false + + + + + + + 51 + false + + 3. + -3. + 5. + -5. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Amount + + + + + 52 + false + + 100. + 0. + 0. + -91445760000000000,50.,0,0,0,0,0,0 + 8 + false + false + false + + Midpoint + + + + + 53 + false + + 100. + -100. + 0. + -91445760000000000,0.,0,0,0,0,0,0 + 8 + false + false + false + + Roundness + + + + + 54 + false + + 100. + 0. + 0. + -91445760000000000,50.,0,0,0,0,0,0 + 8 + false + false + false + + Feather + + + + + 55 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 12 + false + false + false + + + + + + + 56 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 11 + false + false + false + + SpeedGrade Custom + + + + + 57 + false + + true + false + false + -91445760000000000,true,0,0,0,0,0,0 + 4 + false + false + false + + Custom Layer + + + + + 58 + false + + true + false + false + -91445760000000000,false,0,0,0,0,0,0 + 16 + false + false + false + + unused + + + + + 59 + false + + true + false + false + -91445760000000000,false,0,0,0,0,0,0 + 16 + false + false + false + + unused + + + + + 60 + + 0 + /v4= + -91445760000000000 + 10 + false + false + false + + + + + + 61 + false + + false + false + false + -91445760000000000,false,0,0,0,0,0,0 + 12 + false + false + false + + + + + + + 97 + false + + true + false + false + -91445760000000000,false,0,0,0,0,0,0 + 4 + false + false + false + + + + + + + 98 + + 0 + /v4= + -91445760000000000 + 10 + false + false + false + Embedded LUTs + + + + + 99 + + 0 + AAAAAA== + -91445760000000000 + 10 + false + false + false + Media Embedded LUT type + + + + + 100 + + 0 + /v4= + -91445760000000000 + 10 + false + false + false + Media Embedded Lut blob + + + 0. + 100. + 10. + 0 + 1 + false + + + false + 100. + 0. + 0. + 4 + + 100 + 0 + 1. + 0 + 0 + 1 + 1 + false + + + 0 + false + false + false + 100. + 1 + false + + + false + 15. + 0. + 0. + 1 + 40 + + 1 + + 0 + 1. + 0 + 0 + 1 + 1 + false + + + 0 + 0 + 2 + 0 + 40 + false + 15. + 0. + 0. + 7 + 0 + 1. + 0 + 0 + 1 + 1 + false + + + false + 1 + 0 + 1. + 0 + 1 + false + + + 1 + 0 + 0 + false + 0 + 1 + false + + + 200. + 12. + -2. + -24. + 0 + 0 + eyJjdXN0b21EYXRhIjp7InVzZVNjZW5hcmlvIjoyfSwibUFsbG93ZWRDaGFubmVsTGF5b3V0VmVjdG9yIjpbW3siY2hhbm5lbGxhYmVsIjowfV0sW3siY2hhbm5lbGxhYmVsIjoxMDB9LHsiY2hhbm5lbGxhYmVsIjoxMDF9XSxbeyJjaGFubmVsbGFiZWwiOjEwMH0seyJjaGFubmVsbGFiZWwiOjEwMX0seyJjaGFubmVsbGFiZWwiOjEwMn0seyJjaGFubmVsbGFiZWwiOjEwM30seyJjaGFubmVsbGFiZWwiOjEwNH0seyJjaGFubmVsbGFiZWwiOjEwNX1dXSwibUNoYW5uZWxMYXlvdXRWZWN0b3IiOltdLCJtTWF4TnVtQXVkaW9DaGFubmVscyI6MzIsIm1NYXhOdW1BdWRpb0NoYW5uZWxzUGVyU3RyZWFtIjozMiwibU1heE51bUF1ZGlvU3RyZWFtcyI6MzIsIm1WZXJzaW9uIjoxfQ== + + false + false + false + 2. + 1 + false + + + 1 + + + + + + 0 + 0 + + + + Captions + ADBECaptionTabGroup + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 10 + 0 + + + 1 + + + + + + + + + + + + + ADBECaptionExportOption + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 2 + 0 + + + + + ADBECaptionFormat + false + false + false + false + false + false + false + false + false + true + false + false + 0 + false + 1 + 2 + 0 + + + + + ADBECaptionFrameRate + false + false + false + false + false + false + false + false + false + true + false + false + 0 + false + 2 + 2 + 102 + + + + + ADBECaptionStreamFormat + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 3 + 2 + 1330660686 + + + + + + ADBECaptionMetaDataGroup + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 4 + 8 + 0 + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ADBESTLCodePageNumber + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 0 + 2 + 0 + + + + + ADBESTLDiskFormatCode + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 1 + 2 + 0 + + + + + ADBESTLDisplayStandardCode + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 2 + 2 + 1 + + + + + ADBESTLCharacterCodeTableNumber + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 3 + 2 + 0 + + + + + ADBESTLLanguageCode + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 4 + 2 + 9 + + + + + ADBESTLOriginalProgrammeTitle + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 5 + 6 + + + + + + ADBESTLOriginalEpisodeTitle + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 6 + 6 + + + + + + ADBESTLTranslatedProgrammeTitle + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 7 + 6 + + + + + + ADBESTLTranslatedEpisodeTitle + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 8 + 6 + + + + + + ADBESTLTranslatorsName + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 9 + 6 + + + + + + ADBESTLTranslatorsContactDetails + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 10 + 6 + + + + + + ADBESTLSubtitleListReferenceCode + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 11 + 6 + + + + + + ADBESTLCreationDate + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 12 + 6 + + + + + + ADBESTLRevisionDate + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 13 + 6 + + + + + + ADBESTLRevisionNumber + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 14 + 2 + 0 + + + + + ADBESTLMaxCharsInRow + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 15 + 2 + 40 + + + + + ADBESTLDisplayableRows + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 16 + 2 + 24 + + + + + ADBESTLTimeCodeStatus + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 17 + 1 + false + + + + + ADBESTLStartOfProgramme + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 18 + 6 + 00:00:00:00 + + + + + ADBESTLCountryOfOrigin + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 19 + 6 + + + + + + ADBESTLPublisher + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 20 + 6 + + + + + + ADBESTLEditorsName + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 21 + 6 + + + + + + ADBESTLEditorsContactDetails + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 22 + 6 + + + + + + ADBESTLCustomText + false + false + false + false + false + false + false + false + false + false + false + false + 0 + false + 23 + 6 + + + + + + ADBEHiddenTimeDisplay + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 24 + 2 + 101 + + + + + ADBESRTIncludeStyling + false + false + false + false + false + false + false + false + true + true + false + false + 0 + false + 5 + 1 + false + + diff --git a/pype/premiere/extensions/com.pype.avalon/encoding/prores422.epr b/pype/premiere/extensions/com.pype/encoding/prores422.epr similarity index 100% rename from pype/premiere/extensions/com.pype.avalon/encoding/prores422.epr rename to pype/premiere/extensions/com.pype/encoding/prores422.epr diff --git a/pype/premiere/extensions/com.pype.avalon/icons/iconDarkNormal.png b/pype/premiere/extensions/com.pype/icons/iconDarkNormal.png similarity index 100% rename from pype/premiere/extensions/com.pype.avalon/icons/iconDarkNormal.png rename to pype/premiere/extensions/com.pype/icons/iconDarkNormal.png diff --git a/pype/premiere/extensions/com.pype.avalon/icons/iconDarkRollover.png b/pype/premiere/extensions/com.pype/icons/iconDarkRollover.png similarity index 100% rename from pype/premiere/extensions/com.pype.avalon/icons/iconDarkRollover.png rename to pype/premiere/extensions/com.pype/icons/iconDarkRollover.png diff --git a/pype/premiere/extensions/com.pype.avalon/icons/iconDisabled.png b/pype/premiere/extensions/com.pype/icons/iconDisabled.png similarity index 100% rename from pype/premiere/extensions/com.pype.avalon/icons/iconDisabled.png rename to pype/premiere/extensions/com.pype/icons/iconDisabled.png diff --git a/pype/premiere/extensions/com.pype.avalon/icons/iconNormal.png b/pype/premiere/extensions/com.pype/icons/iconNormal.png similarity index 100% rename from pype/premiere/extensions/com.pype.avalon/icons/iconNormal.png rename to pype/premiere/extensions/com.pype/icons/iconNormal.png diff --git a/pype/premiere/extensions/com.pype.avalon/icons/iconRollover.png b/pype/premiere/extensions/com.pype/icons/iconRollover.png similarity index 100% rename from pype/premiere/extensions/com.pype.avalon/icons/iconRollover.png rename to pype/premiere/extensions/com.pype/icons/iconRollover.png diff --git a/pype/premiere/extensions/com.pype/index_remote.html b/pype/premiere/extensions/com.pype/index_remote.html new file mode 100644 index 00000000000..024c6a96f71 --- /dev/null +++ b/pype/premiere/extensions/com.pype/index_remote.html @@ -0,0 +1,21 @@ + + + + + + Avalon + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pype/premiere/extensions/com.pype/jsx/JavaScript.d.ts b/pype/premiere/extensions/com.pype/jsx/JavaScript.d.ts new file mode 100644 index 00000000000..b7aab1e5048 --- /dev/null +++ b/pype/premiere/extensions/com.pype/jsx/JavaScript.d.ts @@ -0,0 +1,2708 @@ +/** + * The $ object provides a number of debugging facilities and informational methods. + */ +interface $ { + /** + * The ExtendScript build information. + */ + readonly build: string + + /** + * The ExtendScript build date. + */ + readonly buildDate: Date + + /** + * The character used as the decimal point character in formatted numeric output. + */ + decimalPoint: string + + /** + * The name of the current ExtendScript engine, if set. + */ + readonly engineName: string + + /** + * The most recent run-time error information. + * Assigning error text to this property generates a run-time error; however, the preferred way to generate a run-time error is to throw an Error object. + */ + error: Error + + /** + * The file name of the current script. + */ + readonly fileName: string + + /** + * Gets or sets low-level debug output flags. + * A logical AND of bit flag values: + * 0x0002 (2): Displays each line with its line number as it is executed. + * 0x0040 (64): Enables excessive garbage collection. Usually, garbage collection starts when the number of objects has increased by a certain amount since the last garbage collection. This flag causes ExtendScript to garbage collect after almost every statement. This impairs performance severely, but is useful when you suspect that an object gets released too soon. + * 0x0080 (128): Displays all calls with their arguments and the return value. + * 0x0100 (256): Enables extended error handling (see strict). + * 0x0200 (512): Enables the localization feature of the toString method. Equivalent to the localize property. + */ + flags: number + + /** + * A reference to the global object, which contains the JavaScript global namespace. + */ + readonly global: any + + /** + * A high-resolution timer, measuring the time in microseconds. The timer starts when ExtendScript is + * initialized during the application startup sequence. Every read access resets the timer to Zero. + */ + readonly hiresTimer: number + + /** + * The path for include files for the current script. + */ + readonly includePath: string + + /** + * The current debugging level, which enables or disables the JavaScript debugger. + * One of 0 (no debugging), 1 (break on runtime errors), or 2 (full debug mode). + */ + level: number + + /** + * The current line number of the currently executing script. + */ + readonly line: number + + /** + * Gets or sets the current locale. + * The string contains five characters in the form LL_RR, where LL is an ISO 639 language specifier, and RR is an ISO 3166 region specifier.Initially, this is the value that the application or the platform returns for the current user. You can set it to temporarily change the locale for testing. To return to the application or platform setting, set to undefined, null, or the empty string. + */ + locale: string + + /** + * Set to true to enable the extended localization features of the built-in toString() method. + */ + localize: boolean + + /** + * The ExtendScript memory cache size, in bytes. + */ + memCache: number + + /** + * The current operating system version information. + */ + readonly os: string + + /** + * An array of objects containing information about the display screens attached to your computer. + * Each object has the properties left, top, right, bottom, which contain the four corners of each screen in global coordinates.A property primary is true if that object describes the primary display. + */ + readonly screens: object[] + + /** + * The current stack trace. + */ + readonly stack: string + + /** + * Sets or clears strict mode for object modification. + * When true, any attempt to write to a read-only property causes a runtime error. Some objects do not permit the creation of new properties when true. + */ + strict: any + + /** + * The version number of the ExtendScript engine. + * Formatted as a three-part number and description; for example: "3.92.95 (debug)". + */ + readonly version: string + + /** + * Shows an About box for the ExtendScript component, and returns the text for the box. + */ + about(): string + + /** + * Breaks execution at the current position. + * @param condition A string containing a JavaScript statement to be used as a condition. If the statement evaluates to true or nonzero when this point is reached, execution stops. + */ + bp(condition?: any): void + + /** + * Invokes the platform-specific color selection dialog, and returns the selected color. + * @param color The color to be preselected in the dialog, as 0xRRGGBB, or -1 for the platform default. + */ + colorPicker(color: number): number + + /** + * Loads and evaluates a file. + * @param file The file to load. + * @param timeout An optional timeout in milliseconds. + */ + evalFile(file: File, timeout?: number): any + + /** + * Initiates garbage collection in the ExtendScript engine. + */ + gc(): void + + /** + * Retrieves the value of an environment variable. + * @param name The name of the variable. + */ + getenv(name: string): string + + /** + * Sets the value of an environment variable. + * @param name The name of the variable. + * @param value The value of the variable. + */ + setenv(name: string, value: string): void + + /** + * Suspends the calling thread for a number of milliseconds. + * During a sleep period, checks at 100 millisecond intervals to see whether the sleep should be terminated. This can happen if there is a break request, or if the script timeout has expired. + * @param msecs Number of milliseconds to sleep. + */ + sleep(msecs: number): void + + /** + * Converts this object to a string. + */ + toString(): string + + /** + * Prints text to the Console. + * @param text The text to print. All arguments are concatenated. + */ + write(text: any): void + + /** + * Prints text to the Console, and adds a newline character. + * @param text The text to print. All arguments are concatenated. + */ + writeln(text: any): void +} +declare const $: $ + +interface ObjectConstructor { + readonly prototype: Object + + /** + * Creates and returns a new object of a given type. + * @param what The object type. + */ + new (what: any): Object + (): any + (what: any): any + + /** + * Reports whether an object is still valid. + * @param what The object to check. + */ + isValid(what: Object): boolean +} +declare const Object: ObjectConstructor + +/** + * The base class of all JavaScript objects. + */ +interface Object { + /** + * Points to the constructor function that created this object. + * Note that this property is treated as an XML element in the XML class. + */ + readonly constructor: Function + + /** + * Points to the prototype object for this object. + * Note that this property is treated as an XML element in the XML class. + */ + readonly prototype: Object + + /** + * Retrieves and returns the Reflection object associated with this method or a property. + * Note that this property is treated as an XML element in the XML class. + */ + readonly reflect: Reflection + + /** + * Reports whether a given property is defined with an instance or within the prototype chain. + * @param name The name of the property to check. + */ + hasOwnProperty(name: string): boolean + + /** + * Checks whether the given object is a prototype of this object. + * @param what The object to check. + */ + isPrototypeOf(what: Object): boolean + + /** + * Reports whether a given property is enumerable. + * @param name The name of the property to check. + */ + propertyIsEnumerable(name: string): boolean + + /** + * Creates and returns a string representing this object, localized for the current locale. See toString(). + */ + toLocaleString(): string + + /** + * Creates and returns a string representation of this object. + * This function serializes the object, so that it can, for example, be passed between engines. Pass the returned string back to eval() to recreate the object. Works only with built-in classes. + */ + toSource(): string + + /** + * Creates and returns a string representing this object. + * Many objects (such as Date) override this method in favor of their own implementation. If an object has no string value and no user-defined toString() method, the default method returns [object type], where type is the object type or the name of the constructor function that created the object. + */ + toString(): string + + /** + * Removes the watch function of a property. + * @param name The name of the property to unwatch. + */ + unwatch(name: string): void + + /** + * Retrieves and returns the primitive value of this object. + * If the object has no primitive value, returns the object itself.Note that you rarely need to call this method yourself.The JavaScript interpreter automatically invokes it when encountering an object where a primitive value is expected. + */ + valueOf(): Object + + /** + * Adds a watch function to a property, which is called when the value changes. + * This function can accept, modify, or reject a new value that the user, application, or a script has attempted to place in a property. + * @param name The name of the property to watch. + * @param func The function to be called when the value of this property changes. This function must three arguments, and return as its result the value to be stored in the property. The arguments are: name: the name of the property that changes. oldValue: The old property value. newValue: The new property value that was specified. + */ + watch(name: string, func: Function): void +} + +interface ArrayConstructor { + readonly prototype: Array + + /** + * Creates and returns a new array. + * Takes any number of parameters, which become the elements of the array, or a single value which becomes the length of an empty array. Note that you cannot create a one-element array, as the single parameter value is interpreted as the length. Returns the new array. + * @param arrayLength If no other parameters are passed, the initial length of the empty array. Otherwise, the first element. + * @param values If there is more than one parameter, the array is initialized with the given parameters. + */ + new (arrayLength?: number): any[] + new (arrayLength: number): T[] + new (...values: T[]): T[] + (arrayLength?: number): any[] + (arrayLength: number): T[] + (...values: T[]): T[] +} +declare const Array: ArrayConstructor + +/** + * An array with integer indexing and a length property. + */ +interface Array { + [n: number]: T + + /** + * The length of the array + */ + length: number + + /** + * Returns a new array created by concatenating the given values to the end of the original array. + * The original array is unchanged.If an array is provided as a parameter to concat(), each of its elements are appended as separate array elements at the end of the new array.Returns a new array, the result of concatenation the given values to the end of the original array. + * @param values Any number of values to be added to the end of the array. Can also be arrays. + */ + concat(...values: T[][]): T[] + + /** + * Joins all elements of the array into a string; optionally, each element is separated by delimiter. + * Returns the string containing the joined elements and delimiters. + * @param delimiter A string used to separate each element of the array. If omitted, the array elements are separated with a comma. + */ + join(delimiter?: string): string + + /** + * Removes the last element from the array, decreases the length by 1, and returns the value of the element. + * Returns the value of the deleted array element. + */ + pop(): T | undefined + + /** + * Places one or more values onto the end of the array and increases length by n. + * Returns the new length of the array. + * @param values Any number of values to be pushed onto the end of the array. + */ + push(...values: T[]): number + + /** + * Reverses the order of the elements in the array. + * Returns the reversed array. + */ + reverse(): T[] + + /** + * Removes the first element from the array, decreases the length by 1, and returns the value of the element. + * Returns the value of the deleted array element. + */ + shift(): T | undefined + + /** + * Creates a new array, which contains a subset of the original array's elements. + * The slice begins with the index start, and continues up to, but not including the index, end.If start or end is a negative number, the indexed is resolved counting backwards from the end of the array resulting in the element array[array. length + negativeIndex]. Returns a new array containing elements array[start] through array[end-1]. + */ + slice(start?: number, end?: number): T[] + + /** + * Sorts the elements of the array in place, using the given function to compare to elements. + * If no function is provided, the elements are sorted alphabetically.Returns no return value. + * @param userFunction A user-supplied function of the form userFunction(a, b) which returns less than 0 if a is greater than b, 0 if a and b are equal, and greater than 0 if b is greater than a. + */ + sort(userFunction?: (a: T, b: T) => number): this + + /** + * Removes num elements from the array beginning with index, start. + * Optionally insert new elements beginning at index start.To ensure contiguity, elements are moved up to fill in any gaps.Returns a new array containing any elements deleted from the original array. + * @param start The index of the first element to remove. Negative values are relative to the end of the array. + * @param deleteCount The number of array elements to remove, including start. If omitted, all elements from array index start to the end of the array are removed. + * @param values A list of one or more values to be added to the array starting at index start. Must specify a value for num, to use this argument. + */ + splice(start: number, deleteCount?: number, ...values: T[]): T[] + + /** + * Converts an array to a string and returns the string (localized). + */ + toLocaleString(): string + + /** + * Creates a string representation of this object that can be fed back to eval() to re-create an object. Works only with built-in classes. + */ + toSource(): string + + /** + * Converts an array to a string and returns the string. + * Yields the same result as array. join() when called without a parameter.Returns a comma-separated list of all the elements of the array. + */ + toString(): string + + /** + * Adds one or more elements to the beginning of the array. + * Returns the new array length. + * @param values The values of one or more elements to be added to the beginning of the array. + */ + unshift(...values: T[]): number +} + +/** + * A global object containing a set of math functions and constants. + */ +interface Math { + /** + * Euler's constant and the base of natural logarithms. + */ + readonly E: number + + /** + * The natural logarithm of 10. + */ + readonly LN10: number + + /** + * The natural logarithm of 2. + */ + readonly LN2: number + + /** + * The base 10 logarithm of e. + */ + readonly LOG10E: number + + /** + * The base 2 logarithm of e. + */ + readonly LOG2E: number + + /** + * The ratio of the circumference of a circle to its diameter. + */ + readonly PI: number + + /** + * The reciprocal of the square root of 1/2. + */ + readonly SQRT1_2: number + + /** + * The square root of 2. + */ + readonly SQRT2: number + + /** + * Returns the absolute value of a number. + * @param x A number. + */ + abs(x: number): number + + /** + * Returns the arc cosine(in radians) of a number. + * @param x A number. + */ + acos(x: number): number + + /** + * Returns the arc sin(in radians) of a number. + * @param x A number. + */ + asin(x: number): number + + /** + * Returns the arc tangent(in radians) of a number. + * @param x A number. + */ + atan(x: number): number + + /** + * Returns the arc tangent of the quotient of its arguments (y/x). + * @param y A number. + * @param x A number. + */ + atan2(y: number, x: number): number + + /** + * Rounds the number up to the nearest integer. + * @param x A number. + */ + ceil(x: number): number + + /** + * Returns the cosine of an angle provided in radians. + * @param x An angle, in radians. + */ + cos(x: number): number + + /** + * Returns Math.E raised to the power of a number. + * @param x A number. + */ + exp(x: number): number + + /** + * Rounds a number down to the nearest integer. + * @param x A number. + */ + floor(x: number): number + + /** + * Returns the natural logarithm of a number. + * @param x A number. + */ + log(x: number): number + + /** + * Returns the largest of zero or more numbers. + * @param rest Numbers. + */ + max(...rest: number[]): number + + /** + * Returns the smallest of zero or more numbers. + * @param rest Numbers. + */ + min(...rest: number[]): number + + /** + * Returns x raised to the power of y. + * @param x Numbers. + * @param y + */ + pow(x: number, y: number): number + + /** + * Returns a pseudo-random number from 0.0 up to but not including 1.0. + */ + random(): number + + /** + * Rounds a number to the nearest integer. + * @param x A number. + */ + round(x: number): number + + /** + * Returns the sine of an angle provided in radians. + * @param x An angle, in radians. + */ + sin(x: number): number + + /** + * Returns the square root of a number. + * @param x A number. + */ + sqrt(x: number): number + + /** + * Returns the tangent of an angle provided in radians. + * @param x An angle, in radians. + */ + tan(x: number): number +} +declare const Math: Math + +interface DateConstructor { + readonly prototype: Date + + /** + * Returns a new Date object holding the current date and time. + * If parameters are supplied, returns a new Date object holding the supplied date and time. + * @param year The year expressed in four digits. + * @param month An integer value from 0 (Jan) to 11 (Dec). + * @param day An integer value from 1 to 31, If this argument is not supplied, its value is set to 0. + * @param hours An integer value from 0 (midnight) to 23 (11 PM). If this argument is not supplied, its value is set to 0. + * @param min An integer value from 0 to 59. If this argument is not supplied, its value is set to 0. + * @param sec An Integer value from 0 to 59. If this argument is not supplied, its value is set to 0. + * @param ms An integer value from 0 to 999. If this argument is not supplied, its value is set to 0. + */ + new (): Date + new (value: number): Date + new (value: string): Date + new ( + year: number, + month: number, + day?: number, + hours?: number, + min?: number, + sec?: number, + ms?: number, + ): Date + + /** + * Parses a string, returning a new Date object. The string should be similar to the string returned bt toString(). + * @param text The string to parse. + */ + parse(text: string): Date + + /** + * Returns the number of milliseconds between midnight January 1, 1970, UTC, and the specified time. + * @param year The year expressed in four digits, for example, 2001. To indicate for a year from 1900 to 1999, you can specify a value from 0 to 99. + * @param month An integer value from 0 (Jan) to 11 (Dec). + * @param day An integer value from 1 to 31, If this argument is not supplied, its value is set to 0. + * @param hours An integer value from 0 (midnight) to 23 (11 PM). If this argument is not supplied, its value is set to 0. + * @param min An integer value from 0 to 59. If this argument is not supplied, its value is set to 0. + * @param sec An Integer value from 0 to 59. If this argument is not supplied, its value is set to 0. + * @param ms An integer value from 0 to 999. If this argument is not supplied, its value is set to 0. + */ + UTC( + year: number, + month?: number, + day?: number, + hours?: number, + min?: number, + sec?: number, + ms?: number, + ): Date +} +declare const Date: DateConstructor + +/** + * A date/time object. + */ +interface Date { + /** + * Returns the day of the month of the specified Date object in local time. + */ + getDate(): number + + /** + * Returns the day of the week for the specified Date object in local time. + * This is an integer from 0 (Sunday) to 6 (Saturday).Returns the day of the week for date. + */ + getDay(): number + + /** + * Returns the four digit year of the specified Date object in local time. + */ + getFullYear(): number + + /** + * Returns the hour of the specified Date object in local time. + */ + getHours(): number + + /** + * Returns the milliseconds of the specified Date object in local time. + */ + getMilliseconds(): number + + /** + * Returns the minutes of the specified Date object in local time. + */ + getMinutes(): number + + /** + * Returns the month of the specified Date object in local time. + */ + getMonth(): number + + /** + * Returns the seconds of the specified Date object in local time. + */ + getSeconds(): number + + /** + * Returns the number of milliseconds since midnight January 1,1970 UTC for the specified Date object. + */ + getTime(): number + + /** + * Returns the difference in minutes between the computer's local time and UTC. + */ + getTimezoneOffset(): number + + /** + * Returns the day of the month of the specified Date object according to UTC. + */ + getUTCDate(): number + + /** + * Returns the day of the week for the specified Date object according to UTC. + */ + getUTCDay(): number + + /** + * Returns the four digit year of the specified Date object according to UTC. + */ + getUTCFullYear(): number + + /** + * Returns the hour of the specified Date object according to UTC. + */ + getUTCHours(): number + + /** + * Returns the milliseconds of the specified Date object according to UTC. + */ + getUTCMilliseconds(): number + + /** + * Returns the minutes of the specified Date object according to UTC. + */ + getUTCMinutes(): number + + /** + * Returns the month of the specified Date object according to UTC. + */ + getUTCMonth(): number + + /** + * Returns the seconds of the specified Date object according to UTC. + */ + getUTCSeconds(): number + + /** + * Returns the year of the specified Date object, as a difference from 1900, in local time. + */ + getYear(): number + + /** + * Sets the day of the month of a specified Date object according to local time. + * Returns the number of milliseconds between the new date and midnight, January 1, 1970. + * @param date An integer from 1 to 31 indicating the day of the month. + */ + setDate(date: number): number + + /** + * Sets the year of a specified Date object according to local time. + * This method can also set month and date if those arguments are specified. Returns the number of milliseconds between the new date and midnight, January 1, 1970. + * @param year A four-digit integer value indicating the year to set. + */ + setFullYear(year: number): number + + /** + * Sets the hours of a specified Date object according to local time. + * Returns the number of milliseconds between the new date and midnight, January 1, 1970. + * @param hour An integer value from 0 (midnight) to 23 (11 PM). + */ + setHours(hour: number): number + + /** + * Sets the milliseconds of a specified Date object according to local time. + * Returns the number of milliseconds between the new date and midnight, January 1, 1970. + * @param ms An integer value from 0 to 999. + */ + setMilliseconds(ms: number): number + + /** + * Sets the minutes of a specified Date object according to local time. + * Returns the number of milliseconds between the new date and midnight, January 1, 1970. + * @param minutes An integer value from 0 to 59. + */ + setMinutes(minutes: number): number + + /** + * Sets the month of a specified Date object according to local time. + * Returns the number of milliseconds between the new date and midnight, January 1, 1970. + * @param month An integer value from 0 (Jan) to 11 (Dec). + */ + setMonth(month: number): number + + /** + * Sets the seconds of a specified Date object according to local time. + * Returns the number of milliseconds between the new date and midnight, January 1, 1970. + * @param seconds An integer value from 0 to 59. + */ + setSeconds(seconds: number): number + + /** + * Sets the date of a specified Date object in milliseconds since midnight, January 1, 1970. + * Returns the value of ms. + * @param ms An integer indicating the number of milliseconds between the date set and midnight, January 1, 1970. + */ + setTime(ms: number): number + + /** + * Sets the date of a specified Date object according to universal time. + * Returns the number of milliseconds between the new date and midnight, January 1, 1970 in UTC time. + * @param date An integer from 1 to 31 indicating the day of the month. + */ + setUTCDate(date: number): number + + /** + * Sets the year of a specified Date object according to UTC, can also set the month and date. + * Returns the number of milliseconds between the date set and midnight, January 1, 1970, in UTC. + * @param year The year expressed in four digits. + */ + setUTCFullYear(year: number): number + + /** + * Sets the hours of a specified Date object according to UTC. + * Returns the number of milliseconds between the date set and midnight, January 1, 1970, in UTC. + * @param hours An integer value from 0 (midnight) to 23 (11 PM) indicating the hour to be set. + */ + setUTCHours(hours: number): number + + /** + * Sets the milliseconds of a specified Date object according to UTC. + * Returns the number of milliseconds between the date set and midnight, January 1, 1970, in UTC. + * @param ms An integer value in the range of 0 to 999 indicating the number of milliseconds to set. + */ + setUTCMilliseconds(ms: number): number + + /** + * Sets the minutes of a specified Date object according to UTC. + * Returns the number of milliseconds between the date set and midnight, January 1, 1970, in UTC. + * @param min An integer value in the range 0 to 59 indicating the number of minutes to be set. + */ + setUTCMinutes(min: number): number + + /** + * Sets the month of a specified Date object according to UTC. + * Returns the number of milliseconds between the date set and midnight, January 1, 1970, in UTC. + * @param month An integer value in the range 0 (Jan.) to 11 (Dec.) indicating the month to set. + */ + setUTCMonth(month: number): number + + /** + * Sets the seconds of a specified Date object according to UTC. + * Returns the number of milliseconds between the date set and midnight, January 1, 1970, in UTC. + * @param sec An integer value in the range 0 to 59 indicating the number of seconds to set. + */ + setUTCSeconds(sec: number): number + + /** + * Sets the year of a specified Date object according to local time, as a difference between the current year and 1900. + * Returns the number of milliseconds between the date set and midnight, January 1, 1970. + * @param year An integer value indicating the year to set. The method interprets a 1- or 2- digit value to mean the 1900s; for example, 13 is interpreted to mean 1913. + */ + setYear(year: number): number + + /** + * Returns the date as a string. + */ + toDateString(): string + + /** + * Returns the date and time adjusted to GMT (UTC) as a string. + */ + toGMTString(): string + + /** + * Returns the date as a localized string. + */ + toLocaleDateString(): string + + /** + * Returns a string value representing the date and time stored in the Date object in human readable format (localized). + */ + toLocaleString(): string + + /** + * Returns the time as a localized string. + */ + toLocaleTimeString(): string + + /** + * Creates a string representation of this object that can be fed back to eval() to re-create an object. Works only with built-in classes. + */ + toSource(): string + + /** + * Returns a string value representing the date and time stored in the Date object in human readable format. + * Returns the following string is an example of the format returned by this method: Mon Aug 13, 10:54:21 GMT-0700 2001. + */ + toString(): string + + /** + * Returns the time as a string. + */ + toTimeString(): string + + /** + * Returns the date and time adjusted to UTC as a string. + */ + toUTCString(): string + + /** + * The valueOf() method returns the number of milliseconds that have passed since midnight, Returns an integer. + */ + valueOf(): number +} + +interface FunctionConstructor { + readonly prototype: Function + + /** + * The Function constructor parses the argument list and creates a Function object. + * @param arguments The list of formal arguments, separated by commas. The formal arguments can also be supplied one by one; in this case, the last argument to the Function constructor is considered to be the function body. + * @param body The body of the function to create. + */ + new (arguments: string, body: string): Function + (arguments: string, body: string): Function +} +declare const Function: FunctionConstructor + +/** + * Wraps a built-in or JavaScript function. + */ +interface Function { + /** + * The function arguments, packed into an array. + * This property is deprecated; use the arguments property within the function body. + */ + arguments: object + + /** + * The number of formal arguments. + * This property is deprecated; use the length property instead. + */ + readonly arity: number + + /** + * The number of formal arguments. + */ + readonly length: number + + /** + * The function name. + */ + readonly name: string + + /** + * Apply a this object and an argument list to a function. + * This function is different from call(); here, the arguments are suppliedas an Array object. + * @param thisObj The object to be used as this. + * @param args An array of arguments. + */ + apply(thisObj: object, args: any): any + + /** + * Apply a this object and arguments to a function. + * This function is different from apply(); here, the arguments are supplied one by one. + * @param thisObj The object to be used as this. + * @param arguments The first agument to the function. Add as many as needed. + */ + call(thisObj: object, ...arguments: any[]): any + + /** + * Creates a string representation of this object that can be fed back to eval() to re-create an object. Works only with JavaScript functions. + */ + toSource(): string + + /** + * Returns the function definition as a string. + */ + toString(): string +} + +interface StringConstructor { + readonly prototype: String + + /** + * Returns a string representation of the value given as an argument. + * @param value A number, variable, or object to convert to a string. + */ + new (value?: any): String + (value: any): string + + /** + * Returns a string created by concatenation one or more characters specified as ASCII values. + * @param value1 One or more ASCII values. + */ + fromCharCode(value1: number): string +} +declare const String: StringConstructor + +/** + * A character string. Each character is adressable by index. + */ +interface String { + /** + * The length of the string. + */ + readonly length: number + + /** + * Get character at index. + */ + readonly [index: number]: string + + /** + * Returns a string consisting of this string enclosed in a tag. + * @param name The text to be stored in the anchors' name attribute. + */ + anchor(name: string): string + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + big(): string + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + blink(): string + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + bold(): string + + /** + * Returns the character at the specified index. + * @param index An integer between 0 and string.length -1, specifying the character to return. + */ + charAt(index: number): string + + /** + * Returns the Unicode value of the character at the given index. + * @param index An integer between 0 and string.length -1, specifying the character. + */ + charCodeAt(index: number): number + + /** + * If necessary, converts the one or more given values to strings. + * Those values are concatenated with the original string, the result is returned. The original string is not effected.Returns the concatenated string. + * @param value The values to be concatenated with the given string. + */ + concat(value: string): string + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + fixed(): string + + /** + * Returns a string consisting of this string enclosed in a tag. + * @param color The value to be stored in the tag's color attribute. + */ + fontcolor(color: string): string + + /** + * Returns a string consisting of this string enclosed in a tag. + * @param size The value to be stored in the tag's size attribute. + */ + fontsize(size: number): string + + /** + * Returns the index within the string of the first occurrence of the specified string, starting the search at fromIndex if provided. + * @param searchValue The string for which to search. + * @param offset The starting offset of the search. + */ + indexOf(searchValue: string, offset?: number): number + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + italics(): string + + /** + * Returns the index within the string of the last occurrence of the specified value. + * The string is searched backward, starting at fromIndex.Returns the index within the string where the last occurrence of searchValue was found, or -1 if it was not found. + * @param searchValue The string for which to search. + * @param offset The starting offset of the search. + */ + lastIndexOf(searchValue: string, offset?: number): number + + /** + * Returns a string consisting of this string enclosed in a tag. + * @param href The value to be stored in the tag's href attribute. + */ + link(href: string): string + + /** + * Performs a localized comparison of two strings. + * @param what The string to compare with. + */ + localeCompare(what: string): number + + /** + * Matches a string against a regular expression. + * @param regexp The regular expression to use. + */ + match(regexp: RegExp | string): RegExpMatchArray | null + + /** + * + * @param what + * @param with_ + */ + replace(what: any, with_: string): string + + /** + * + * @param search + */ + search(search: RegExp): number + + /** + * Extracts a substring of the given string and returns it as a new string. + * The substring begins at startSlice, and includes all characters up to, but not including the character at the index endSlice. A negative value indexes from the end of the string.For example, a negative value for startSlice is resolved as: string. length + startSlice.The original string is unchanged.Returns a substring of characters from the given string, starting at startSlice and ending with endSlice-1. + * @param startSlice The index at which to begin extraction. + * @param endSlice The index at which to end extraction. If omitted, slice extracts to the end of the string. + */ + slice(startSlice: number, endSlice?: number): string + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + small(): string + + /** + * Splits a string into a group of substrings, places those strings in an array, and returns the array. + * The substrings are created by breaking the original string at places that match delimiter, the delimiter characters are removed.Returns an array whose elements are the substrings. + * @param delimiter Specifies the string to use for delimiting. If delimiter is omitted, the array returned contains one element, consisting of the entire string. + * @param limit + */ + split(delimiter: string, limit?: number): string[] + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + strike(): string + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + sub(): string + + /** + * Returns a string containing the characters beginning at the specified index, start, through the specified number of characters. + * The original string is unchanged.Returns a string containing the extracted characters. + * @param start Location at which to begin extracting characters. + * @param length The number of characters to extract. + */ + substr(start: number, length?: number): string + + /** + * Returns a substring of the given string by extracting characters from indexA up to but not including indexB. + * The original string is unchanged.Returns a substring of characters from the given string, starting at indexA and ending with indexB-1. + * @param indexA The index to begin extracting. + * @param indexB The index at which to end extraction. If omitted, slice extracts to the end of the string. + */ + substring(indexA: number, indexB?: number): string + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + sup(): string + + /** + * Returns a new string which contains all the characters of the original string converted to lowercase (localized). + * The original string is unchanged. + */ + toLocaleLowerCase(): string + + /** + * Returns a new string which contains all the characters of the original string converted to uppercase (localized). + * The original string is unchanged. + */ + toLocaleUpperCase(): string + + /** + * Returns a new string which contains all the characters of the original string converted to lowercase. + * The original string is unchanged. + */ + toLowerCase(): string + + /** + * Creates a string representation of this object that can be fed back to eval() to re-create an object. Works only with built-in classes. + */ + toSource(): string + + /** + * Returns itself. + */ + toString(): string + + /** + * Returns a new string which contains all the characters of the original string converted to uppercase. + * The original string is unchanged. + */ + toUpperCase(): string + + /** + * The valueOf() method returns the number of milliseconds that have passed since midnight, Returns an integer. + */ + valueOf(): string +} + +interface NumberConstructor { + readonly prototype: Number + + /** + * Returns a new Number object set to the value of the argument converted to a number. + * @param value The value of the object being created. + */ + new (value?: any): Number + (value: any): number + + /** + * A constant representing the largest representable number. + */ + readonly MAX_VALUE: number + + /** + * A constant representing the smallest representable number. + */ + readonly MIN_VALUE: number + + /** + * A constant representing negative infinity. + */ + readonly NEGATIVE_INFINITY: number + + /** + * A constant representing the special "Not a Number" value. + */ + readonly NaN: number + + /** + * A constant representing positive infinity. + */ + readonly POSITIVE_INFINITY: number +} +declare const Number: NumberConstructor + +/** + * Wraps a numeric value. + */ +interface Number { + /** + * Converts the Number object to a string in scientific notation. + * @param decimals The number of decimals. + */ + toExponential(decimals: number): string + + /** + * Converts the Number object to a string with fixed decimals. + * @param decimals The number of decimals. + */ + toFixed(decimals: number): string + + /** + * Returns the value of a Number object converted to a string, using localized conventions. + */ + toLocaleString(): string + + /** + * Converts the Number object to a string in either scientific or fixed notation, epending on its value. + * @param decimals The number of decimals. + */ + toPrecision(decimals: number): string + + /** + * Creates a string representation of this object that can be fed back to eval() to re-create an object. Works only with built-in classes. + */ + toSource(): string + + /** + * Returns the value of a Number object converted to a string. + * @param radix The optional conversion radix. + */ + toString(radix?: number): string + + /** + * Returns the value of a Number object as a primitive number. + */ + valueOf(): number +} + +interface BooleanConstructor { + readonly prototype: Boolean + + /** + * Creates and returns a new Boolean object set to the value of the argument converted to a boolean. + * @param value The value to be converted to a Boolean. + */ + new (value?: any): Boolean + (value: any): boolean +} +declare const Boolean: BooleanConstructor + +/** + * Wraps a Boolean value. + */ +interface Boolean { + /** + * Creates a string representation of this object that can be fed back to eval() to re-create an object. Works only with built-in classes. + */ + toSource(): string + + /** + * Returns the string representation of the value of bool. + * The method returns the string true if the primitive value of bool is true; otherwise it returns the string false. + */ + toString(): string + + /** + * Returns the primitive value of bool. + * The method returns true if the primitive value of bool is true; otherwise it returns false. + */ + valueOf(): boolean +} + +interface RegExpConstructor { + readonly prototype: RegExp + + /** + * Creates and returns a new RegExp object set to the value of the argument converted to a regular expression. + * @param pattern The pattern to convert. + * @param flags Flags that control how the conversion is performed. A string containing any combination of the letters i, m, g: "i" -- ignore case in pattern matching "m" -- treat the string as multiple lines "g" -- do global pattern matching + */ + new (pattern: string | RegExp, flags?: string): RegExp + (pattern: string | RegExp, flags?: string): RegExp + + /** + * The matched subexpression #1. + */ + readonly $1: string + + /** + * The matched subexpression #2. + */ + readonly $2: string + + /** + * The matched subexpression #3. + */ + readonly $3: string + + /** + * The matched subexpression #4. + */ + readonly $4: string + + /** + * The matched subexpression #5. + */ + readonly $5: string + + /** + * The matched subexpression #6. + */ + readonly $6: string + + /** + * The matched subexpression #7. + */ + readonly $7: string + + /** + * The matched subexpression #8. + */ + readonly $8: string + + /** + * The matched subexpression #9. + */ + readonly $9: string + + /** + * Indicates whether the match is a global match. + */ + global: boolean + + /** + * Indicates whether the match is not case sensitive. + */ + ignoreCase: boolean + + /** + * The original input string. + */ + input: string + + /** + * The last match. + */ + readonly lastMatch: string + + /** + * The value of the last matched subexpression. + */ + readonly lastParen: string + + /** + * The string before the match. + */ + readonly leftContext: string + + /** + * Indicates whether the match matches multiple lines. + */ + multiline: boolean + + /** + * The string after the match. + */ + readonly rightContext: string +} +declare const RegExp: RegExpConstructor + +/** + * Wraps a regular expression. + */ +interface RegExp { + /** + * Compiles a string to a regular expression. Returns true if the compilation was successful. + * @param pattern The pattern to compile. + */ + compile(pattern: string): boolean + + /** + * Execute a regular expression. + * The return value is an array of matches, with the first element containing the match, and successive elements containing the results of any matching subexpression in their order of appearance. If there is no match, the result is null. + * @param text The string to match. + */ + exec(text: string): RegExpExecArray | null + + /** + * Execute a regular expression, and return true if there is a match. + * @param text The string to match. + */ + test(text: string): boolean + + /** + * Converts this RegExp object to a string. + */ + toString(): string +} + +interface RegExpMatchArray extends Array { + index?: number + input?: string +} + +interface RegExpExecArray extends Array { + index: number + input: string +} + +interface ErrorConstructor { + readonly prototype: Error + + /** + * Creates a new Error object. + * @param msg The error message. + * @param file The name of the file. + * @param line The line number. + */ + new (msg: string, file?: string, line?: number): Error + (msg: string, file?: string, line?: number): Error +} +declare const Error: ErrorConstructor + +/** + * Wraps a runtime error. + */ +interface Error { + /** + * The error message. + */ + description: string + + /** + * Creates a string representation of this object that can be fed back to eval() to re-create an object. Works only with built-in classes. + */ + toSource(): string + + /** + * Convert this object to a string. + */ + toString(): string +} + +interface FileConstructor { + readonly prototype: File + + /** + * Creates and returns a new File object referring to a given file system location. + * @param path The full or partial path name of the file,in platform-specific or URI format. The value stored in the object is the absolute path. The file that the path refers to does not need to exist.If the path refers to an existing folder: The File function returns a Folder object instead of a File object. The new operator returns a File object for a nonexisting file with the same name. + */ + new (path?: string): File + (path?: string): File + + /** + * The name of the file system. + * This is a class property accessed through the File constructor. Valid values are "Windows", "Macintosh", and "Unix". + */ + readonly fs: string + + /** + * Decodes a UTF-8 encoded string as required by RFC 2396, and returns the decoded string. + * See also String.decodeURI(). + * @param uri The UTF-8 encoded string to decode. + */ + decode(uri: string): string + + /** + * Encodes a string as required by RFC 2396, and returns the encoded string. + * All special characters are encoded in UTF-8 and stored as escaped characters starting with the percent sign followed by two hexadecimal digits. For example, the string "my file" is encoded as "my%20file". + * Special characters are those with a numeric value greater than 127, except the following: / - _ . ! ~ * ' ( ) + * See also encodeURI(). + * @param name The string to encode. + */ + encode(name: string): string + + /** + * Reports whether a given encoding is available. + * @param name The encoding name. Typical values are "ASCII", "binary", or "UTF-8".For a complete list of supported encodings, see the JavaScript Tools Guide. + */ + isEncodingAvailable(name: string): boolean + + /** + * Opens a dialog so the user can select one or more files to open. + * Opens the built-in platform-specific file-browsing dialog in which a user can select an existing file or multiple files, and creates new File objects to represent the selected files. + * If the user clicks OK, returns a File object for the selected file, or an array of objects if multiple files are selected. + * If the user cancels, returns null. + * @param prompt The prompt text, displayed if the dialog allows a prompt. + * @param filter A filter that limits the types of files displayed in the dialog. In Windows,a filter expression such as "Javascript files:*.jsx;All files:*.*". In Mac OS, a filter function that takes a File instance and returns true if the file should be included in the display, false if it should not. + * @param multiSelect When true, the user can select multiple files and the return value is an array. + */ + openDialog(prompt?: string, filter?: any, multiSelect?: boolean): File + + /** + * Opens a dialog so the user can select a file name to save to. + * Opens the built-in platform-specific file-browsing dialog in which a user can select an existing file location to which to save information, and creates a new File object to represent the selected file location. + * If the user clicks OK, returns a File object for the selected file location. + * If the user cancels, returns null. + * @param prompt The prompt text, displayed if the dialog allows a prompt. + * @param filter In Windows only, a filter that limits the types of files displayed in the dialog. In Windows only,a filter expression such as "Javascript files:*.jsx;All files:*.*". Not used In Mac OS. + */ + saveDialog(prompt?: string, filter?: any): File +} +declare const File: FileConstructor + +/** + * Represents a file in the local file system in a platform-independent manner. + */ +interface File { + /** + * The full path name for the referenced file in URI notation. + */ + readonly absoluteURI: string + + /** + * If true, the object refers to a file system alias or shortcut. + */ + readonly alias: boolean + + /** + * The creation date of the referenced file, or null if the object does not refer to a file on disk. + */ + readonly created: Date + + /** + * In Mac OS, the file creator as a four-character string. In Windows or UNIX, value is "????". + */ + readonly creator: string + + /** + * The localized name of the referenced file, without the path specification. + */ + readonly displayName: string + + /** + * Gets or sets the encoding for subsequent read/write operations. + * One of the encoding constants listed in the JavaScript Tools Guide. If the value is not recognized, uses the system default encoding.A special encoder, BINARY, is used to read binary files. It stores each byte of the file as one Unicode character regardless of any encoding. When writing, the lower byte of each Unicode character is treated as a single byte to write. + */ + encoding: string + + /** + * When true, a read attempt caused the current position to be at the end of the file, or the file is not open. + */ + readonly eof: boolean + + /** + * A string containing a message describing the most recent file system error. + * Typically set by the file system, but a script can set it. Setting this value clears any error message and resets the error bit for opened files. Contains the empty string if there is no error. + */ + error: string + + /** + * If true, this object refers to a file or file-system alias that actually exists in the file system. + */ + readonly exists: boolean + + /** + * The platform-specific full path name for the referenced file. + */ + readonly fsName: string + + /** + * The full path name for the referenced file in URI notation. + */ + readonly fullName: string + + /** + * When true, the file is not shown in the platform-specific file browser. + * If the object references a file-system alias or shortcut, the flag is altered on the alias, not on the original file. + */ + hidden: boolean + + /** + * The size of the file in bytes. + * Can be set only for a file that is not open, in which case it truncates or pads the file with 0-bytes to the new length. + */ + length: number + + /** + * How line feed characters are written in the file system. + * One of the values "Windows", "Macintosh", or "Unix". + */ + lineFeed: string + + /** + * The date of the referenced file's last modification, or null if the object does not refer to a file on the disk. + */ + readonly modified: Date + + /** + * The file name portion of the absolute URI for the referenced file, without the path specification. + */ + readonly name: string + + /** + * The Folder object for the folder that contains this file. + */ + readonly parent: Folder + + /** + * The path portion of the absolute URI for the referenced file, without the file name. + */ + readonly path: string + + /** + * When true, prevents the file from being altered or deleted. + * If the referenced file is a file-system alias or shortcut, the flag is altered on the alias, not on the original file. + */ + readonly: boolean + + /** + * The path name for the object in URI notation, relative to the current folder. + */ + readonly relativeURI: string + + /** + * The file type as a four-character string. + * In Mac OS, the Mac OS file type. + * In Windows, "appl" for .EXE files, "shlb" for .DLL files and "TEXT" for any other file. + */ + readonly type: string + + /** + * Changes the path specification of the referenced file. + * @param path A string containing the new path, absolute or relative to the current folder. + */ + changePath(path: string): boolean + + /** + * Closes this open file. + * Returns true if the file was closed successfully, false if an I/O error occurred. + */ + close(): boolean + + /** + * Copies this object’s referenced file to the specified target location. + * Resolves any aliases to find the source file. If a file exists at the target location, it is overwritten. + * Returns true if the copy was successful. + * @param target A string with the URI path to the target location, or a File object that references the target location. + */ + copy(target: string): boolean + + /** + * Makes this file a file-system alias or shortcut to the specified file. + * The referenced file for this object must not yet exist on disk. Returns true if the operation was successful. + * @param path A string containing the path of the target file. + */ + createAlias(path: string): void + + /** + * Executes or opens this file using the appropriate application, as if it had been double-clicked in a file browser. + * You can use this method to run scripts, launch applications, and so on.Returns true immediately if the application launch was successful. + */ + execute(): boolean + + /** + * Retrieves and returns the path for this file, relative to the specified base path, in URI notation. + * If no base path is supplied, the URI is relative to the path of the current folder.Returns a string containing the relative URI. + * @param basePath A base path in URI notation. + */ + getRelativeURI(basePath: string): string + + /** + * Opens the referenced file for subsequent read/write operations. The method resolves any aliases to find the file. + * Returns true if the file was opened successfully.The method attempts to detect the encoding of the open file. It reads a few bytes at the current location and tries to detect the Byte Order Mark character 0xFFFE. If found, the current position is advanced behind the detected character and the encoding property is set to one of the strings UCS-2BE, UCS-2LE, UCS4-BE, UCS-4LE, or UTF-8. If the marker character is not found, it checks for zero bytes at the current location and makes an assumption about one of the above formats (except UTF-8). If everything fails, the encoding property is set to the system encoding. + * IMPORTANT: Be careful about opening a file more than once. The operating system usually permits you to do so, but if you start writing to the file using two different File objects, you can destroy your data. + * @param mode The read-write mode, a single-character string. One of these characters: r (read) Opens for reading. If the file does not exist or cannot be found, the call fails. w (write) Opens a file for writing. If the file exists, its contents are destroyed. If the file does not exist, creates a new, empty file. e (edit) Opens an existing file for reading and writing. a (append) Opens an existing file for reading and writing, and moves the current position to the end of the file. + * @param type In Mac OS, the type of a newly created file, a 4-character string. Ignored in Windows and UNIX. + * @param creator In Mac OS, the creator of a newly created file, a 4-character string. Ignored in Windows and UNIX. + */ + open(mode: string, type?: string, creator?: string): boolean + + /** + * Opens the built-in platform-specific file-browsing dialog, in which the user can select an existing file or files, and creates new File objects to represent the selected files. + * Differs from the class method openDialog() in that it presets the current folder to this File object’s parent folder and the current file to this object’s associated file. + * If the user clicks OK, returns a File or Folder object for the selected file or folder, or an array of objects. + * If the user cancels, returns null. + * @param prompt A string containing the prompt text, if the dialog allows a prompt. + * @param filter A filter that limits the types of files displayed in the dialog. In Windows,a filter expression such as "Javascript files:*.jsx;All files:*.*". In Mac OS, a filter function that takes a File instance and returns true if the file should be included in the display, false if it should not. + * @param multiSelect When true, the user can select multiple files and the return value is an array. + */ + openDlg(prompt?: string, filter?: any, multiSelect?: boolean): File + + /** + * Reads the contents of the file, starting at the current position. + * Returns a string that contains up to the specified number of characters. If a number of characters is not supplied, reads from the current position to the end of the file. If the file is encoded, multiple bytes might be read to create single Unicode characters. + * @param chars An integer specifying the number of characters to read. + */ + read(chars?: number): string + + /** + * Reads a single text character from the file at the current position. + * Line feeds are recognized as CR, LF, CRLF or LFCR pairs.If the file is encoded, multiple bytes might be read to create a single Unicode character. Returns a string that contains the character. + */ + readch(): string + + /** + * Reads a single line of text from the file at the current position. + * Line feeds are recognized as CR, LF, CRLF or LFCR pairs.. If the file is encoded, multiple bytes might be read to create single Unicode characters. Returns a string that contains the text. + */ + readln(): string + + /** + * Deletes the file associated with this object from disk immediately, without moving it to the system trash. + * Does not resolve aliases; instead, deletes the referenced alias or shortcut file itself. Returns true if the file was successfully removed. + * IMPORTANT: Cannot be undone. It is recommended that you prompt the user for permission before deleting. + */ + remove(): boolean + + /** + * Renames the associated file. + * Does not resolve aliases, but renames the referenced alias or shortcut file itself. Returns true if the file was successfully renamed. + * @param newName The new file name, with no path information. + */ + rename(newName: string): boolean + + /** + * Attempts to resolve the file-system alias or shortcut that this object refers to. + * If successful, creates and returns a new File object that points to the resolved file system element. Returns null if this object does not refer to an alias, or if the alias could not be resolved. + */ + resolve(): File + + /** + * Opens the built-in platform-specific file-browsing dialog, in which the user can select an existing file location to which to save information, and creates a new File object to represent the selected file. + * Differs from the class method saveDialog() in that it presets the current folder to this File object’s parent folder and the file to this object’s associated file. + * If the user clicks OK, returns a File object for the selected file. + * If the user cancels, returns null. + * @param prompt A string containing the prompt text, if the dialog allows a prompt. + * @param filter In Windows only, a filter that limits the types of files displayed in the dialog. In Windows only,a filter expression such as "Javascript files:*.jsx;All files:*.*". Not used In Mac OS. + */ + saveDlg(prompt?: string, filter?: any): File + + /** + * Seeks to a given position in the file. + * The new position cannot be less than 0 or greater than the current file size. Returns true if the position was changed. + * @param pos The new current position in the file as an offset in bytes from the start, current position, or end, depending on the mode. + * @param mode The seek mode. One of: 0: Seek to absolute position, where pos=0 is the first byte of the file. This is the default. 1: Seek relative to the current position. 2. Seek backward from the end of the file. + */ + seek(pos: number, mode?: number): boolean + + /** + * Retrieves the current position as a byte offset from the start of the file. + * Returns a number, the position index. + */ + tell(): number + + /** + * Creates and returns a serialized string representation of this object. + * Pass the resulting string to eval() to recreate the object. + */ + toSource(): string + + /** + * Converts this object to a string. + */ + toString(): string + + /** + * Writes the specified text to the file at the current position. + * You can supply multiple text values; the strings are concatenated to form a single string.For encoded files, writing a single Unicode character may write multiple bytes. Returns true if the write was successful.IMPORTANT: Be careful not to write to a file that is open in another application or object, as this can overwrite existing data. + * @param text A text string to be written. + */ + write(text: string): boolean + + /** + * Writes a string to the file at the current position and appends a line-feed sequence. + * You can supply multiple text values. The strings are concatenated into a single string, which is written in the file followed by one line-feed sequence, of the style specified by this object's linefeed property.For encoded files, writing a single Unicode character may write multiple bytes.Returns true if the write was successful.IMPORTANT: Be careful not to write to a file that is open in another application or object, as this can overwrite existing data. + * @param text A text string to be written. + */ + writeln(text: string): boolean +} + +interface FolderConstructor { + readonly prototype: Folder + + /** + * Creates and returns a new Folder object referring to a given file-system location. + * If the path name refers to an already existing disk file, a File object is returned instead.Returns the new Folder object. + * @param path The absolute or relative path to the folder associated with this object, specified in URI format. The value stored in the object is the absolute path.The path need not refer to an existing folder. If the path refers to an existing file, rather than a folder: The Folder() function returns a File object instead of a Folder object. The new operator returns a Folder object for a nonexisting folder with the same name. + */ + new (path?: string): Folder + (path?: string): Folder + + /** + * The folder containing the application data for all users. + * In Windows, the value of %APPDATA% (by default, C:\\Documents and Settings\\All Users\\Application Data) + * In Mac OS, /Library/Application Support + */ + readonly appData: Folder + + /** + * In Mac OS, a Folder object for the folder containing the bundle of the running application. + */ + readonly appPackage: Folder + + /** + * A Folder object for the folder containing common files for all programs installed by the user. + * In Windows, the value of %CommonProgramFiles% (by default, C:\\Program Files\\Common Files) + * In Mac OS, /Library/Application Support + */ + readonly commonFiles: Folder + + /** + * A Folder object for the current folder. + * Assign a Folder object or a string containing the new path name to set the current folder. This is a class property accessed through the Folder constructor. + */ + current: Folder + + /** + * A Folder object for the folder that contains the user’s desktop. + * In Windows, C:\\Documents and Settings\\username\\Desktop + * In Mac OS, ~/Desktop + */ + readonly desktop: Folder + + /** + * The name of the current file system. + * One of "Windows", "Macintosh", or "Unix". + */ + readonly fs: string + + /** + * A folder pointing to the user's My Documents folder. + * In Windows, C:\\Documents and Settings\\username\\My Documents + * In Mac OS,~/Documents + */ + readonly myDocuments: Folder + + /** + * A Folder object for the folder containing the executable image of the running application. + */ + readonly startup: Folder + + /** + * A Folder object for the folder containing the operating system files. + * In Windows, the value of %windir% (by default, C:\\Windows) + * In Mac OS, /System + */ + readonly system: Folder + + /** + * A Folder object for the default folder for temporary files. + */ + readonly temp: Folder + + /** + * A Folder object for the folder containing deleted items. On Windows, the trash folder is a virtual + * folder containing a database; therefore, the property value is null on Windows. + */ + readonly trash: Folder + + /** + * A Folder object for the folder containing the user's application data. + * In Windows, the value of %USERDATA% (by default, C:\\Documents and Settings\\username\\Application Data) + * In Mac OS,~/Library/Application Support. + */ + readonly userData: Folder + + /** + * Decodes a UTF-8 encoded string as required by RFC 2396, and returns the decoded string. + * See also String.decodeURI(). + * @param uri The UTF-8 string to decode. + */ + decode(uri: string): string + + /** + * Encodes a string as required by RFC 2396, and returns the encoded string. + * All special characters are encoded in UTF-8 and stored as escaped characters starting with the percent sign followed by two hexadecimal digits. For example, the string "my file" is encoded as "my%20file". + * Special characters are those with a numeric value greater than 127, except the following: / - _ . ! ~ * ' ( ) + * See also encodeURI(). + * @param name The string to encode. + */ + encode(name: string): string + + /** + * Reports whether a given encoding is available. + * @param name The encoding name. Typical values are "ASCII", "binary", or "UTF-8".For a complete list of supported encodings, see the JavaScript Tools Guide. + */ + isEncodingAvailable(name: string): boolean + + /** + * Opens the built-in platform-specific file-browsing dialog, and creates a new File or Folder object for the selected file or folder. + * Differs from the object method selectDlg() in that it does not preselect a folder. + * If the user clicks OK, returns a File or Folder object for the selected file or folder. + * If the user cancels, returns null. + * @param prompt The prompt text, if the dialog allows a prompt. + */ + selectDialog(prompt?: string): Folder +} +declare const Folder: FolderConstructor + +/** + * Represents a file-system folder or directory in a platform-independent manner. + */ +interface Folder { + /** + * The full path name for the referenced folder in URI notation. + */ + readonly absoluteURI: string + + /** + * When true, the object refers to a file system alias or shortcut. + */ + readonly alias: boolean + + /** + * The creation date of the referenced folder, or null if the object does not refer to a folder on disk. + */ + readonly created: Date + + /** + * The localized name portion of the absolute URI for the referenced folder, without the path specification. + */ + readonly displayName: string + + /** + * A message describing the most recent file system error. + * Typically set by the file system, but a script can set it. Setting this value clears any error message and resets the error bit for opened files. Contains the empty string if there is no error. + */ + error: string + + /** + * When true, this object refers to a folder that currently exists in the file system. + */ + readonly exists: boolean + + /** + * The platform-specific name of the referenced folder as a full path name. + */ + readonly fsName: string + + /** + * The full path name for the referenced folder in URI notation. . + */ + readonly fullName: string + + /** + * The date of the referenced folder's last modification, or null if the object does not refer to a folder on disk. + */ + readonly modified: Date + + /** + * The folder name portion of the absolute URI for the referenced file, without the path specification. + */ + readonly name: string + + /** + * TThe Folder object for the folder that contains this folder, or null if this object refers to the root folder of a volume. + */ + readonly parent: Folder + + /** + * The path portion of the object absolute URI for the referenced file, without the folder name. + */ + readonly path: string + + /** + * The path name for the referenced folder in URI notation, relative to the current folder. + */ + readonly relativeURI: string + + /** + * Changes the path specification of the referenced folder. + * @param path A string containing the new path, absolute or relative to the current folder. + */ + changePath(path: string): boolean + + /** + * Creates a folder at the location given by this object's path property. + * Returns true if the folder was created. + */ + create(): boolean + + /** + * Opens this folder in the platform-specific file browser (as if it had been double-clicked in the file browser). + * Returns true immediately if the folder was opened successfully. + */ + execute(): boolean + + /** + * Retrieves the contents of this folder, filtered by the supplied mask. + * Returns an array of File and Folder objects, or null if this object's referenced folder does not exist. + * @param mask A search mask for file names, specified as a string or a function. A mask string can contain question mark (?) and asterisk (*) wild cards. Default is "*", which matches all file names. Can also be the name of a function that takes a File or Folder object as its argument. It is called for each file or folder found in the search; if it returns true, the object is added to the return array. NOTE: In Windows, all aliases end with the extension .lnk. ExtendScript strips this from the file name when found, in order to preserve compatibility with other operating systems. You can search for all aliases by supplying the search mask "*.lnk", but note that such code is not portable. + */ + getFiles(mask: any): Array + + /** + * Retrieves and returns the path for this file, relative to the specified base path, in URI notation. + * If no base path is supplied, the URI is relative to the path of the current folder.Returns a string containing the relative URI. + * @param basePath A base path in URI notation. + */ + getRelativeURI(basePath?: string): string + + /** + * Deletes the folder associated with this object from disk immediately, without moving it to the system trash. + * Folders must be empty before they can be deleted. Does not resolve aliases; instead, deletes the referenced alias or shortcut file itself. Returns true if the file was successfully removed. + * IMPORTANT: Cannot be undone. It is recommended that you prompt the user for permission before deleting. + */ + remove(): boolean + + /** + * Renames the associated folder. + * Does not resolve aliases, but renames the referenced alias or shortcut file itself. Returns true if the folder was successfully renamed. + * @param newName The new folder name, with no path information. + */ + rename(newName: string): boolean + + /** + * Attempts to resolve the file-system alias or shortcut that this object refers to. + * If successful, creates and returns a new Folder object that points to the resolved file system element. Returns null if this object does not refer to an alias, or if the alias could not be resolved. + */ + resolve(): Folder + + /** + * Opens the built-in platform-specific file-browsing dialog, and creates a new File or Folder object for the selected file or folder. + * Differs from the class method selectDialog() in that it preselects this folder. + * If the user clicks OK, returns a File or Folder object for the selected file or folder. + * If the user cancels, returns null. + * @param prompt The prompt text, if the dialog allows a prompt. + */ + selectDlg(prompt?: string): Folder + + /** + * Creates and returns a serialized string representation of this object. + * Pass the resulting string to eval() to recreate the object. + */ + toSource(): string + + /** + * Converts this object to a string. + */ + toString(): string +} + +interface SocketConstructor { + readonly prototype: Socket + + /** + * Creates a new Socket object. + */ + new (): Socket + (): Socket +} +declare const Socket: SocketConstructor + +/** + * Creates a TCP/IP connection, or establishes a TCP/IP server. + */ +interface Socket { + /** + * When true, the connection is active. + */ + readonly connected: boolean + + /** + * Sets or retrieves the name of the encoding used to transmit data. + * Typical values are "ASCII", "BINARY", or "UTF-8". + */ + encoding: string + + /** + * When true, the receive buffer is empty. + */ + readonly eof: boolean + + /** + * A message describing the most recent error. Setting this value clears any error message. + */ + error: string + + /** + * The name of the remote computer when a connection is established. + * If the connection is shut down or does not exist, the property contains the empty string. + */ + readonly host: string + + /** + * The timeout in seconds to be applied to read or write operations. + */ + timeout: number + + /** + * Terminates the open connection. + * Returns true if the connection was closed, false on I/O errors. + * Deleting the object also closes the connection, but not until JavaScript garbage-collects the object. The connection might stay open longer than you wish if you do not close it explicitly. + */ + close(): boolean + + /** + * Instructs the object to start listening for an incoming connection. + * The call to open() and the call to listen()are mutually exclusive. Call one function or the other, not both. + * @param port The TCP/IP port number to listen on. Valid port numbers are 1 to 65535. Typical values are 80 for a Web server, 23 for a Telnet server and so on. + * @param encoding The encoding to be used for the connection Typical values are "ASCII", "BINARY", or "UTF-8". + */ + listen(port: number, encoding?: string): boolean + + /** + * Opens the connection for subsequent read/write operations. + * The call to open() and the call to listen() are mutually exclusive. Call one function or the other, not both. + * @param host The server to connect to. This can be a DNS name, an IPv4 address, or an IPv6 address, followed by a colon and a port number. + * @param encoding The encoding to be used for the connection Typical values are "ASCII", "binary", or "UTF-8". + */ + open(host: string, encoding?: string): boolean + + /** + * Checks a listening object for a new incoming connection. + * If a connection request was detected, the method returns a new Socket object that wraps the new connection. Use this connection object to communicate with the remote computer. After use, close the connection and delete the JavaScript object. If no new connection request was detected, the method returns null. + */ + poll(): Socket + + /** + * Reads up to the specified number of characters from the connection. CR characters are ignored unless the encoding is set to "BINARY". + * Returns a string that contains up to the number of characters that were supposed to be read, or the number of characters read before the connection closed or timed out. + * @param count The number of characters to read. If not supplied, the connection attempts to read as many characters it can get and returns immediately. + */ + read(count?: number): string + + /** + * Reads one line of text up to the next line feed. + * Line feeds are recognized as LF or CRLF pairs. CR characters are ignored. Returns a string containing the characters. + */ + readln(): string + + /** + * Concatenates all arguments into a single string and writes that string to the connection. + * @param text Any number of string values. All arguments are concatenated to form the string to be written. CRLF sequences are converted to LFs unless the encoding is set to "BINARY". + */ + write(text: string): boolean + + /** + * Concatenates all arguments into a single string, appends a LF character, and writes that string to the connection. + * @param text Any number of string values. All arguments are concatenated to form the string to be written. CRLF sequences are converted to LFs unless the encoding is set to "BINARY". + */ + writeln(text: string): boolean +} + +/** + * Provides information about a method, a property or a method parameters. + */ +interface ReflectionInfo { + /** + * The description of method or function arguments. + */ + readonly arguments: ReflectionInfo[] + + /** + * The data type. + */ + readonly dataType: string + + /** + * The default value. + */ + readonly defaultValue: any + + /** + * The long description text. + */ + readonly description: string + + /** + * The short description text. + */ + readonly help: string + + /** + * Contains true if the class describes a collection class. + */ + readonly isCollection: boolean + + /** + * The maximum value. + */ + readonly max: number + + /** + * The minimum value. + */ + readonly min: number + + /** + * The element name. + */ + readonly name: string + + /** + * The class object that this element belongs to. + */ + readonly parent: Reflection + + /** + * Sample code, if present. + */ + readonly sampleCode: string + + /** + * A file containing sample code. May be null. + */ + readonly sampleFile: File + + /** + * The element type. + * One of unknown, readonly, readwrite, createonly, method or parameter. + */ + readonly type: string +} +declare const ReflectionInfo: ReflectionInfo + +/** + * Provides information about a class. + */ +interface Reflection { + /** + * The long description text. + */ + readonly description: string + + /** + * The short description text. + */ + readonly help: string + + /** + * An array of method descriptions. + */ + readonly methods: ReflectionInfo[] + + /** + * The class name. + */ + readonly name: string + + /** + * An array of property descriptions. + */ + readonly properties: ReflectionInfo[] + + /** + * Sample code, if present. + */ + readonly sampleCode: string + + /** + * A file containing sample code. May be null. + */ + readonly sampleFile: File + + /** + * An array of class method descriptions. + */ + readonly staticMethods: ReflectionInfo[] + + /** + * An array of class property descriptions. + */ + readonly staticProperties: ReflectionInfo[] + + /** + * Finds an element description by name. + * @param name The name of the element to find. + */ + find(name: string): ReflectionInfo + + /** + * Returns this class information as XML in OMV format. + */ + toXML(): XML +} +declare const Reflection: Reflection + +interface QNameConstructor { + readonly prototype: QName + + /** + * Creates a QName object. + * @param uri The URI, specified as a Namespace object, an existing QName object, or string. If this is a Namespace object, the URI is set to the namespace URI, and there is no local name. If this is a QName object, the URI and localName is set to those of that object. If this is a string, the URI is set to that string. + * @param name The local name. Used only if URI is given as a string. + */ + new (uri: any, name?: string): QName + (uri: any, name?: string): QName +} +declare const QName: QNameConstructor + +/** + * A qualified XML name, containing the URI and the local name. + */ +interface QName { + /** + * The local name part of the qualified name. + */ + readonly localName: string + + /** + * The URI part of the qualified name. + */ + readonly uri: string +} + +interface NamespaceConstructor { + readonly prototype: Namespace + + /** + * Creates a Namespace object. + * @param prefix The URIprefix, specified as an existing Namespace object, QName object, or string. If this is a Namespace or a QName object, the URI and prefix are set to that of the object. If this is a string, the prefix is set to that string, and the URI must be specified. + * @param uri The URI if the prefix is specified as a string. + */ + new (prefix: any, uri?: string): Namespace + (prefix: any, uri?: string): Namespace +} +declare const Namespace: NamespaceConstructor + +/** + * A XML namespace object. + */ +interface Namespace { + /** + * The named prefix. + */ + readonly prefix: string + + /** + * The URI. + */ + readonly uri: string +} + +interface XMLConstructor { + readonly prototype: XML + + /** + * Parses an XML string. Throws an error if the XML is incorrect. + * @param text The text to parse. + */ + new (text: string): XML + (text: string): XML + + /** + * Controls whether XML comments should be parsed (false) or ignored (true). + */ + ignoreComments: boolean + + /** + * Controls whether XML preprocessing instructions should be parsed (false) or ignored (true). + */ + ignoreProcessingInstructions: boolean + + /** + * Controls whether whitespace should be parsed (false) or ignored (true). + */ + ignoreWhitespace: boolean + + /** + * The number of spaces used to indent pretty-printed XML. + */ + prettyIndent: number + + /** + * When true, XML is pretty-printed when converting to a string. + */ + prettyPrinting: boolean + + /** + * Returns an object containing the default parsing and print settings for XML. + */ + defaultSettings(): object + + /** + * Sets the parsing and print setting for XML using an object returned by the settings() method. + * @param obj The object containing the settings to set. + */ + setSettings(obj: object): void + + /** + * Returns an object containing the current parsing and print settings for XML. + */ + settings(): object +} +declare const XML: XMLConstructor + +/** + * Wraps XML into an object. + */ +interface XML { + /** + * Adds a namespace declaration to the node. Returns the XML object itself. + * @param namespace The namespace to add. + */ + addNamespace(namespace: Namespace): XML + + /** + * Appends the given XML to this XML as a child. Returns the XML object itself. + * If the argument is not XML, creates a new XML element containing the argument as text. The element name of that new XML is the same as the last element in the original XML. + * @param child The child XML to add. + */ + appendChild(child: XML): XML + + /** + * Returns a list containing all attribute elements matching the given name. + * @param name The attribute name to look for. + */ + attribute(name: string): XML + + /** + * Returns a list containing all attribute elements. + */ + attributes(): XML + + /** + * Returns a list containing all children of this XML matching the given element name. + * If the argument is a number, uses the number as index into the array of children. + * @param name The name or the index of the child element. + */ + child(name: string): XML + + /** + * Returns a number representing the ordinal position of this XML object within the context of its parent. + */ + childIndex(): number + + /** + * Returns an XML object containing all the properties of this XML object in order. + */ + children(): XML + + /** + * Returns an XML object containing the properties of this XML object that represent XML comments. + */ + comments(): XML + + /** + * Checks if this XML object contains the given XML object. + * @param xml The XML to search for. + */ + contains(xml: XML): boolean + + /** + * Creates a copy of this XML object. + */ + copy(): XML + + /** + * Returns all the XML-valued descendants of this XML object with the given name. + * If the name parameter is omitted, returns all descendants of this XML object. + * @param name The name of the descendant to find. + */ + descendants(name?: string): XML + + /** + * Returns a list of XML children that are elements with a given name, or all children that are XML elements. + * @param name The element name. If not supplied, gets all children that are XML elements. + */ + elements(name?: string): XML + + /** + * Reports whether this XML object contains complex content. + * An XML object is considered to contain complex content if it represents an XML element that has child elements. XML objects representing attributes, comments, processing instructions and text nodes do not have complex content. The existence of attributes, comments, processing instructions and text nodes within an XML object is not significant in determining if it has complex content. + */ + hasComplexContent(): boolean + + /** + * Reports whether this XML object contains simple content. + * An XML object is considered to contain simple content if it represents a text node, represents an attribute node or if it represents an XML element that has no child elements. XML objects representing comments and processing instructions do not have simple content. The existence of attributes, comments, processing instructions and text nodes within an XML object is not significant in determining if it has simple content. + */ + hasSimpleContent(): boolean + + /** + * Returns an array of Namespace objects mirroring the current list of valid namespaces at this element. + * The last element of thereturned array is the default namespace. + */ + inScopeNamespaces(): Namespace[] + + /** + * Inserts the given child2 after the given child1 in this XML object and returns this XML object. + * If child1 is null, the method inserts child2 before all children of this XML object (that is, after none of them). If child1 does not exist in this XML object, the method returns without modifying this XML object. + * @param child1 The child to insert the other child after. If null, the method inserts child2 before all children of this XML object. + * @param child2 The XML to insert. + */ + insertChildAfter(child1: XML, child2: XML): void + + /** + * Inserts the given child2 before the given child1 in this XML object and returns this XML object. + * If child1 is null, the method inserts child2 after all children of this XML object (that is, before none of them). If child1 does not exist in this XML object, the method returns without modifying this XML object. + * @param child1 The child to search for. If null, the method inserts child2 after all children of this XML object. + * @param child2 The XML to insert. + */ + insertChildBefore(child1: XML, child2: XML): void + + /** + * Returns the number of elements contained in an XML list. If this XML object is not a list, returns 1. + */ + length(): number + + /** + * Returns the local name of this XML object. + * This value corresponds to the element name unless the name has a namespace prefix. For example, if the element has the name "ns:tag", the return value is "tag". + */ + localName(): string + + /** + * Returns a QName object containing the URI and the local name of the element. + */ + name(): QName + + /** + * Returns a Namespace object containing the namespace URI of the current element. + */ + namespace(): Namespace + + /** + * Returns an array containing all namespace declarations of this XML object. + */ + namespaceDeclarations(): Namespace[] + + /** + * Returns the type of this XML object as one of the strings "element", "attribute", "comment", "processing-instruction", or "text". + */ + nodeKind(): string + + /** + * Puts all text nodes in this and all descendant XML objects into a normal form by merging adjacent text nodes and eliminating empty text nodes. Returns this XML object. + */ + normalize(): XML + + /** + * Returns the parent object of this XML object. + * The root object, as returned by the XML constructor, does not have a parent and returns null. Note that the E4X standard does not define what happens if this XML object is a list containing elements with multiple parents. + */ + parent(): XML + + /** + * Inserts a given child into this object before its existing XML properties, and returns this XML object. + * @param child The XML to insert. + */ + prependChild(child: XML): XML + + /** + * Returns a list of preprocessing instructions. + * Collects processing-instructions with the given name, if supplied. Otherwise, returns an XML list containing all the children of this XML object that are processing-instructions regardless of their name. + * @param name The name of the preprocessing instruction to return. + */ + processingInstructions(name?: string): XML + + /** + * Removes the given namespace from this XML, and returns this XML. + * @param namespace The namespace to remove. + */ + removeNamespace(namespace: Namespace): XML + + /** + * Replaces the value of specified XML properties of this XML object returns this XML object. + * This method acts like the assignment operator. + * @param name The property name. Can be a numeric property name, a name for a set of XML elements, or the properties wildcard “*”. If this XML object contains no properties that match the name, the method returns without modifying this XML object. + * @param value The XML with which to replace the value of the matching property. Can be an XML object, XML list or any value that can be converted to a String with toString(). + */ + replace(name: string, value: XML): XML + + /** + * Replaces all of the XML-valued properties in this object with a new value, and returns this XML object. + * @param value The new value, which can be a single XML object or an XML list. + */ + setChildren(value: XML): XML + + /** + * Replaces the local name of this XML objectwith a string constructed from the given name + * The local name is any part behind a colon character. If there is no colon, it is the entire name. + * @param name The name to set. + */ + setLocalName(name: string): void + + /** + * Replaces the name of this XML object with the given QName object. + * @param name The fully qualified name. + */ + setName(name: QName): void + + /** + * Sets the namespace for this XML element. + * If the namespace has not been declared in the tree above this element, adds a namespace declaration. + * @param namespace The namespace to set. + */ + setNamespace(namespace: Namespace): void + + /** + * Returns an XML list containing all XML properties of this XML object that represent XML text nodes. + */ + text(): XML + + /** + * Returns the string representation of this object. + * For text and attribute nodes, this is the textual value of the node; for other elements, this is the result of calling the toXMLString() method. If this XML object is a list, concatenates the result of calling toString() on each element. + */ + toString(): string + + /** + * Returns an XML-encoded string representation of this XML object. + * Always includes the start tag, attributes and end tag of the XML object regardless of its content. It is provided for cases when the default XML to string conversion rules are not desired. Interprets the global settings XML.prettyPrint and XML.prettyIndent. + */ + toXMLString(): string + + /** + * Evaluates the given XPath expression in accordance with the W3C XPath recommendation, using this XML object as the context node. + * @param expr The XPath expression to use. + */ + xpath(expr: string): XML +} + +/** + * An XML list object. + * In this implementation, an XMLList object is synonymous to the XML object. The constructor accepts an XML list, but everything else works like theXML object. + */ +interface XMLList {} +declare const XMLList: XMLList + +interface UnitValueConstructor { + readonly prototype: UnitValue + + /** + * Creates a new UnitValue object. + */ + new (value: string | UnitValue): UnitValue + (value: string | UnitValue): UnitValue + + /** + * The base unit for all conversions. + */ + baseUnit: UnitValue +} +declare const UnitValue: UnitValueConstructor + +/** + * Represents a measurement as a combination of values and unit. + * Note that this object is not available in all applications. + */ +interface UnitValue { + /** + * The base unit. + */ + baseUnit: UnitValue + + /** + * The unit name. + */ + readonly type: string + + /** + * The numeric value. + */ + value: number + + /** + * Returns this instance as a different unit. + * @param unitName The unit name. + */ + as(unitName: string): UnitValue + + /** + * Converts this instance to a different unit. + * @param unitName The unit name. + */ + convert(unitName: string): any +} + +/** + * Only for TypeScript compatibility + */ +interface CallableFunction extends Function { + +} + +interface NewableFunction extends Function { + +} + +interface IArguments { + [index: number]: any + length: number + callee: Function +} + +/** + * Make all properties in T optional + */ +type Partial = { [P in keyof T]?: T[P] } + +/** + * Make all properties in T readonly + */ +type Readonly = { readonly [P in keyof T]: T[P] } + +/** + * From T pick a set of properties K + */ +type Pick = { [P in K]: T[P] } + +/** + * Construct a type with a set of properties K of type T + */ +type Record = { [P in K]: T } diff --git a/pype/premiere/extensions/com.pype/jsx/PPRO/Premiere.jsx b/pype/premiere/extensions/com.pype/jsx/PPRO/Premiere.jsx new file mode 100644 index 00000000000..97dbb49bd20 --- /dev/null +++ b/pype/premiere/extensions/com.pype/jsx/PPRO/Premiere.jsx @@ -0,0 +1,3203 @@ +/************************************************************************* + * ADOBE CONFIDENTIAL + * ___________________ + * + * Copyright 2019 Adobe + * All Rights Reserved. + * + * NOTICE: Adobe permits you to use, modify, and distribute this file in + * accordance with the terms of the Adobe license agreement accompanying + * it. If you have received this file from a source other than Adobe, + * then your use, modification, or distribution of it requires the prior + * written permission of Adobe. + **************************************************************************/ + +// time display types + +var TIMEDISPLAY_24Timecode = 100; +var TIMEDISPLAY_25Timecode = 101; +var TIMEDISPLAY_2997DropTimecode = 102; +var TIMEDISPLAY_2997NonDropTimecode = 103; +var TIMEDISPLAY_30Timecode = 104; +var TIMEDISPLAY_50Timecode = 105; +var TIMEDISPLAY_5994DropTimecode = 106; +var TIMEDISPLAY_5994NonDropTimecode = 107; +var TIMEDISPLAY_60Timecode = 108; +var TIMEDISPLAY_Frames = 109; +var TIMEDISPLAY_23976Timecode = 110; +var TIMEDISPLAY_16mmFeetFrames = 111; +var TIMEDISPLAY_35mmFeetFrames = 112; +var TIMEDISPLAY_48Timecode = 113; +var TIMEDISPLAY_AudioSamplesTimecode = 200; +var TIMEDISPLAY_AudioMsTimecode = 201; + +// field type constants + +var FIELDTYPE_Progressive = 0; +var FIELDTYPE_UpperFirst = 1; +var FIELDTYPE_LowerFirst = 2; + +// audio channel types + +var AUDIOCHANNELTYPE_Mono = 0; +var AUDIOCHANNELTYPE_Stereo = 1; +var AUDIOCHANNELTYPE_51 = 2; +var AUDIOCHANNELTYPE_Multichannel = 3; +var AUDIOCHANNELTYPE_4Channel = 4; +var AUDIOCHANNELTYPE_8Channel = 5; + +// vr projection type + +var VRPROJECTIONTYPE_None = 0; +var VRPROJECTIONTYPE_Equirectangular = 1; + +// vr stereoscopic type + +var VRSTEREOSCOPICTYPE_Monoscopic = 0; +var VRSTEREOSCOPICTYPE_OverUnder = 1; +var VRSTEREOSCOPICTYPE_SideBySide = 2; + +// constants used when clearing cache + +var MediaType_VIDEO = '228CDA18-3625-4d2d-951E-348879E4ED93'; // Magical constants from Premiere Pro's internal automation. +var MediaType_AUDIO = '80B8E3D5-6DCA-4195-AEFB-CB5F407AB009'; +var MediaType_ANY = 'FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF'; + +var NOT_SET = '-400000'; + +$._PPP_ = { + createDeepFolderStructure: function(foldersArray, maxDepth) { + if (typeof foldersArray !== 'object' || foldersArray.length <= 0) { + throw new Error('No valid folders array was provided!'); + } + + // if the first folder already exists, throw error + for (var i = 0; i < app.project.rootItem.children.numItems; i++) { + var curChild = app.project.rootItem.children[i]; + var binVal = ProjectItemType.BIN; + if (curChild.type === binVal && curChild.name === foldersArray[0]) { + throw new Error( + 'Folder with name "' + curChild.name + '" already exists!' + ); + } + } + // create the deep folder structure + var currentBin = app.project.rootItem.createBin(foldersArray[0]); + for (var m = 1; m < foldersArray.length && m < maxDepth; i++) { + currentBin = currentBin.createBin(foldersArray[i]); + } + }, + + getVersionInfo: function() { + return 'PPro ' + app.version + 'x' + app.build; + }, + + getUserName: function() { + var homeDir = new File('~/'); + var userName = homeDir.displayName; + homeDir.close(); + return userName; + }, + + keepPanelLoaded: function() { + app.setExtensionPersistent('com.pype', 0); // 0, while testing (to enable rapid reload); 1 for 'Never unload me, even when not visible.' + }, + + updateAllGrowingFiles: function() { + var numItems = app.project.rootItem.children.numItems; + for (var i = 0; i < numItems; i++) { + var currentItem = app.project.rootItem.children[i]; + if (currentItem) { + currentItem.refreshMedia(); + } + } + }, + + getSep: function() { + if (Folder.fs === 'Macintosh') { + return '/'; + } else { + return '\\'; + } + }, + + saveProject: function() { + app.project.save(); + }, + + exportCurrentFrameAsPNG: function() { + app.enableQE(); + var activeSequence = qe.project.getActiveSequence(); // note: make sure a sequence is active in PPro UI + if (activeSequence) { + // Create a file name, based on timecode of frame. + var time = activeSequence.CTI.timecode; // CTI = Current Time Indicator. + var removeThese = /:|;/gi; // Why? Because Windows chokes on colons in file names. + time = time.replace(removeThese, '_'); + var outputPath = new File('~/Desktop'); + var outputFileName = + outputPath.fsName + + $._PPP_.getSep() + + time + + '___' + + activeSequence.name; + activeSequence.exportFramePNG(time, outputFileName); + return outputFileName + } else { + $._PPP_.updateEventPanel('No active sequence.'); + return 'no file was saved' + } + }, + + renameProjectItem: function() { + var item = app.project.rootItem.children[0]; // assumes the zero-th item in the project is footage. + if (item) { + item.name = item.name + ', updated by PProPanel.'; + } else { + $._PPP_.updateEventPanel('No project items found.'); + } + }, + + getActiveSequenceName: function() { + if (app.project.activeSequence) { + return app.project.activeSequence.name; + } else { + return 'No active sequence.'; + } + }, + + projectPanelSelectionChanged: function(eventObj) { + // Note: This message is also triggered when the user opens or creates a new project. + var message = ''; + var projectItems = eventObj; + if (projectItems) { + if (projectItems.length) { + var remainingArgs = projectItems.length; + message = remainingArgs + ' items selected: '; + var view = eventObj.viewID; + + for (var i = 0; i < projectItems.length; i++) { + // Concatenate selected project item names, into message. + message += projectItems[i].name; + remainingArgs--; + if (remainingArgs > 1) { + message += ', '; + } + if (remainingArgs === 1) { + message += ', and '; + } + if (remainingArgs === 0) { + message += '.'; + } + } + } else { + message = 'No items selected.'; + } + } + $._PPP_.updateEventPanel(message); + }, + + registerProjectPanelSelectionChangedFxn: function() { + app.bind( + 'onSourceClipSelectedInProjectPanel', + $._PPP_.projectPanelSelectionChanged + ); + }, + + saveCurrentProjectLayout: function() { + var currentProjPanelDisplay = app.project.getProjectPanelMetadata(); + if (currentProjPanelDisplay) { + var outFileName = 'Previous_Project_Panel_Display_Settings.xml'; + var actualProjectPath = new File(app.project.path); + var projDir = actualProjectPath.parent; + if (actualProjectPath) { + var completeOutputPath = projDir + $._PPP_.getSep() + outFileName; + var outFile = new File(completeOutputPath); + if (outFile) { + outFile.encoding = 'UTF8'; + outFile.open('w', 'TEXT', '????'); + outFile.write(currentProjPanelDisplay); + $._PPP_.updateEventPanel('Saved layout to next to the project.'); + outFile.close(); + } + actualProjectPath.close(); + } + } else { + $._PPP_.updateEventPanel('Could not retrieve current project layout.'); + } + }, + + setProjectPanelMeta: function() { + var filterString = ''; + if (Folder.fs === 'Windows') { + filterString = 'XML files:*.xml'; + } + var fileToOpen = File.openDialog( + 'Choose Project panel layout to open.', + filterString, + false + ); + if (fileToOpen) { + if (fileToOpen.fsName.indexOf('.xml')) { + // We should really be more careful, but hey, it says it's XML! + fileToOpen.encoding = 'UTF8'; + fileToOpen.open('r', 'TEXT', '????'); + var fileContents = fileToOpen.read(); + if (fileContents) { + app.project.setProjectPanelMetadata(fileContents); + $._PPP_.updateEventPanel('Updated layout from .xml file.'); + } + } + } else { + $._PPP_.updateEventPanel('No valid layout file chosen.'); + } + }, + + exportSequenceAsPrProj: function() { + var activeSequence = app.project.activeSequence; + if (activeSequence) { + var startTimeOffset = activeSequence.zeroPoint; + var prProjExtension = '.prproj'; + var outputName = activeSequence.name; + var outFolder = Folder.selectDialog(); + if (outFolder) { + var completeOutputPath = + outFolder.fsName + $._PPP_.getSep() + outputName + prProjExtension; + + app.project.activeSequence.exportAsProject(completeOutputPath); + + $._PPP_.updateEventPanel( + 'Exported ' + + app.project.activeSequence.name + + ' to ' + + completeOutputPath + + '.' + ); + } else { + $._PPP_.updateEventPanel('Could not find or create output folder.'); + } + + // Here's how to import N sequences from a project. + // + // var seqIDsToBeImported = new Array; + // seqIDsToBeImported[0] = ID1; + // ... + // seqIDsToBeImported[N] = IDN; + // + //app.project.importSequences(pathToPrProj, seqIDsToBeImported); + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + createSequenceMarkers: function() { + var activeSequence = app.project.activeSequence; + if (activeSequence) { + var markers = activeSequence.markers; + if (markers) { + var numMarkers = markers.numMarkers; + if (numMarkers > 0) { + var marker_index = 1; + for ( + var current_marker = markers.getFirstMarker(); + current_marker !== undefined; + current_marker = markers.getNextMarker(current_marker) + ) { + if (current_marker.name !== '') { + $._PPP_.updateEventPanel( + 'Marker ' + + marker_index + + ' name = ' + + current_marker.name + + '.' + ); + } else { + $._PPP_.updateEventPanel( + 'Marker ' + marker_index + ' has no name.' + ); + } + $._PPP_.updateEventPanel( + 'Marker ' + marker_index + ' GUID = ' + current_marker.guid + '.' + ); + + if (current_marker.end.seconds > 0) { + $._PPP_.updateEventPanel( + 'Marker ' + + marker_index + + ' duration = ' + + (current_marker.end.seconds - current_marker.start.seconds) + + ' seconds.' + ); + } else { + $._PPP_.updateEventPanel( + 'Marker ' + marker_index + ' has no duration.' + ); + } + $._PPP_.updateEventPanel( + 'Marker ' + + marker_index + + ' starts at ' + + current_marker.start.seconds + + ' seconds.' + ); + marker_index = marker_index + 1; + } + } + } + var tempTime = new Time(); // Until I update the TypeScript definition of Time objects, this'll do... + + var newCommentMarker = markers.createMarker(12.345); + newCommentMarker.name = 'Marker created by PProPanel.'; + newCommentMarker.comments = + 'Here are some comments, inserted by PProPanel.'; + tempTime.seconds = 15.6789; + newCommentMarker.end = tempTime; + + var newWebMarker = markers.createMarker(14.345); + newWebMarker.name = 'Web marker created by PProPanel.'; + newWebMarker.comments = 'Here are some comments, inserted by PProPanel.'; + tempTime.seconds = 17.6789; + newWebMarker.end = tempTime; + newWebMarker.setTypeAsWebLink('http://www.adobe.com', 'frame target'); + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + exportFCPXML: function() { + if (app.project.activeSequence) { + var projPath = new File(app.project.path); + var parentDir = projPath.parent; + var outputName = app.project.activeSequence.name; + var xmlExtension = '.xml'; + var outputPath = Folder.selectDialog('Choose the output directory'); + + if (outputPath) { + var completeOutputPath = + outputPath.fsName + $._PPP_.getSep() + outputName + xmlExtension; + app.project.activeSequence.exportAsFinalCutProXML( + completeOutputPath, + 1 + ); // 1 == suppress UI + var info = + 'Exported FCP XML for ' + + app.project.activeSequence.name + + ' to ' + + completeOutputPath + + '.'; + $._PPP_.updateEventPanel(info); + } else { + $._PPP_.updateEventPanel('No output path chosen.'); + } + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + openInSource: function() { + var filterString = ''; + if (Folder.fs === 'Windows') { + filterString = 'All files:*.*'; + } + var fileToOpen = File.openDialog( + 'Choose file to open.', + filterString, + false + ); + if (fileToOpen) { + app.sourceMonitor.openFilePath(fileToOpen.fsName); + app.sourceMonitor.play(1.73); // playback speed as float, 1.0 = normal speed forward + var position = app.sourceMonitor.getPosition(); // new in 13.0 + $._PPP_.updateEventPanel( + 'Current Source monitor position: ' + position.seconds + ' seconds.' + ); + + /* Example code for controlling scrubbing in Source monitor. + + app.enableQE(); + qe.source.player.startScrubbing(); + qe.source.player.scrubTo('00;00;00;11'); + qe.source.player.endScrubbing(); + qe.source.player.step(); + + qe.source.player.play(playbackSpeed) // playbackSpeed must be between -4.0 and 4.0 + + */ + + fileToOpen.close(); + } else { + $._PPP_.updateEventPanel('No file chosen.'); + } + }, + + searchForBinWithName: function(nameToFind) { + // deep-search a folder by name in project + var deepSearchBin = function(inFolder) { + if (inFolder && inFolder.name === nameToFind && inFolder.type === 2) { + return inFolder; + } else { + for (var i = 0; i < inFolder.children.numItems; i++) { + if (inFolder.children[i] && inFolder.children[i].type === 2) { + var foundBin = deepSearchBin(inFolder.children[i]); + if (foundBin) { + return foundBin; + } + } + } + } + }; + return deepSearchBin(app.project.rootItem); + }, + + importFiles: function() { + var filterString = ''; + if (Folder.fs === 'Windows') { + filterString = 'All files:*.*'; + } + if (app.project) { + var fileOrFilesToImport = File.openDialog( + 'Choose files to import', // title + filterString, // filter available files? + true + ); // allow multiple? + if (fileOrFilesToImport) { + // We have an array of File objects; importFiles() takes an array of paths. + var importThese = []; + if (importThese) { + for (var i = 0; i < fileOrFilesToImport.length; i++) { + importThese[i] = fileOrFilesToImport[i].fsName; + } + app.project.importFiles( + importThese, + true, // suppress warnings + app.project.getInsertionBin(), + false + ); // import as numbered stills + } + } else { + $._PPP_.updateEventPanel('No files to import.'); + } + } + }, + + muteFun: function() { + if (app.project.activeSequence) { + for ( + var i = 0; + i < app.project.activeSequence.audioTracks.numTracks; + i++ + ) { + var currentTrack = app.project.activeSequence.audioTracks[i]; + if (Math.random() > 0.5) { + var muteState = 0; + if (currentTrack.isMuted()) { + muteState = 1; + } + currentTrack.setMute(muteState); + var appendString = 'Muted by PProPanel!'; + currentTrack.name = currentTrack.name + appendString; + } + } + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + disableImportWorkspaceWithProjects: function() { + var prefToModify = 'FE.Prefs.ImportWorkspace'; + var propertyExists = app.properties.doesPropertyExist(prefToModify); + var propertyIsReadOnly = app.properties.isPropertyReadOnly(prefToModify); + var propertyValue = app.properties.getProperty(prefToModify); + + app.properties.setProperty(prefToModify, '0', 1, false); + var safetyCheck = app.properties.getProperty(prefToModify); + if (safetyCheck != propertyValue) { + $._PPP_.updateEventPanel( + 'Changed "Import Workspaces with Projects" from ' + + propertyValue + + ' to ' + + safetyCheck + + '.' + ); + } + }, + + setWorkspace: function() { + var desiredWSName = prompt( + 'Which workspace would you like?', + 'Editing', + 'Which workspace?' + ); + var workspaces = app.getWorkspaces(); + var foundIt = false; + if (workspaces) { + $._PPP_.updateEventPanel(workspaces.length + ' workspaces found.'); + for (var i = 0; i < workspaces.length && foundIt === false; i++) { + var currentWS = workspaces[i]; + if (currentWS === desiredWSName) { + app.setWorkspace(currentWS); + foundIt = true; + $._PPP_.updateEventPanel('Workspace set to ' + currentWS + '.'); + } + } + if (foundIt === false) { + $._PPP_.updateEventPanel( + 'Workspace named ' + desiredWSName + ' was not found.' + ); + } + } + }, + + turnOffStartDialog: function() { + var prefToModify = 'MZ.Prefs.ShowQuickstartDialog'; + var propertyExists = app.properties.doesPropertyExist(prefToModify); + var propertyIsReadOnly = app.properties.isPropertyReadOnly(prefToModify); + var originalValue = app.properties.getProperty(prefToModify); + + app.properties.setProperty(prefToModify, '0', 1, true); // optional 4th param : 0 = non-persistent, 1 = persistent (default) + var safetyCheck = app.properties.getProperty(prefToModify); + if (safetyCheck != originalValue) { + $._PPP_.updateEventPanel('Start dialog now OFF. Enjoy!'); + } else { + $._PPP_.updateEventPanel('Start dialog was already OFF.'); + } + }, + + replaceMedia: function() { + // Note: This method of changing paths for projectItems is from the time + // before PPro supported full-res AND proxy paths for each projectItem. + // This can still be used, and will change the hi-res projectItem path, but + // if your panel supports proxy workflows, it should rely instead upon + // projectItem.setProxyPath() instead. + + var firstProjectItem = app.project.rootItem.children[0]; + if (firstProjectItem) { + if (firstProjectItem.canChangeMediaPath()) { + // NEW in 9.0: setScaleToFrameSize() ensures that for all clips created from this footage, + // auto scale to frame size will be ON, regardless of the current user preference. + // This is important for proxy workflows, to avoid mis-scaling upon replacement. + + // Addendum: This setting will be in effect the NEXT time the projectItem is added to a + // sequence; it will not affect or reinterpret clips from this projectItem, already in + // sequences. + + firstProjectItem.setScaleToFrameSize(); + var filterString = ''; + if (Folder.fs === 'Windows') { + filterString = 'All files:*.*'; + } + var replacementMedia = File.openDialog( + 'Choose new media file, for ' + firstProjectItem.name, + filterString, // file filter + false + ); // allow multiple? + + if (replacementMedia) { + var suppressWarnings = true; + firstProjectItem.name = + replacementMedia.name + + ', formerly known as ' + + firstProjectItem.name; + firstProjectItem.changeMediaPath( + replacementMedia.fsName, + suppressWarnings + ); // new in 12.1 + replacementMedia.close(); + } + } else { + $._PPP_.updateEventPanel( + 'Couldn\'t change path of ' + firstProjectItem.name + '.' + ); + } + } else { + $._PPP_.updateEventPanel('No project items found.'); + } + }, + + openProject: function() { + var filterString = ''; + if (Folder.fs === 'Windows') { + filterString = 'Premiere Pro project files:*.prproj'; + } + var projToOpen = File.openDialog('Choose project:', filterString, false); + if (projToOpen && projToOpen.exists) { + app.openDocument( + projToOpen.fsName, + true, // suppress 'Convert Project' dialogs? + true, // suppress 'Locate Files' dialogs? + true + ); // suppress warning dialogs? + projToOpen.close(); + } + }, + + exportFramesForMarkers: function() { + app.enableQE(); + var activeSequence = app.project.activeSequence; + if (activeSequence) { + var markers = activeSequence.markers; + var markerCount = markers.numMarkers; + if (markerCount) { + var firstMarker = markers.getFirstMarker(); + activeSequence.setPlayerPosition(firstMarker.start.ticks); + $._PPP_.exportCurrentFrameAsPNG(); + + var previousMarker; + if (firstMarker) { + var currentMarker; + for (var i = 0; i < markerCount; i++) { + if (i === 0) { + currentMarker = markers.getNextMarker(firstMarker); + } else { + currentMarker = markers.getNextMarker(previousMarker); + } + if (currentMarker) { + activeSequence.setPlayerPosition(currentMarker.start.ticks); + previousMarker = currentMarker; + $._PPP_.exportCurrentFrameAsPNG(); + } + } + } + } else { + $._PPP_.updateEventPanel( + 'No markers applied to ' + activeSequence.name + '.' + ); + } + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + createSequence: function(name) { + var someID = 'xyz123'; + var seqName = prompt( + 'Name of sequence?', + '<<>>', + 'Sequence Naming Prompt' + ); + app.project.createNewSequence(seqName, someID); + }, + + createSequenceFromPreset: function(presetPath) { + app.enableQE(); + var seqName = prompt( + 'Name of sequence?', + '<<>>', + 'Sequence Naming Prompt' + ); + if (seqName) { + qe.project.newSequence(seqName, presetPath); + } + }, + + transcode: function(outputPresetPath) { + app.encoder.bind('onEncoderJobComplete', $._PPP_.onEncoderJobComplete); + app.encoder.bind('onEncoderJobError', $._PPP_.onEncoderJobError); + app.encoder.bind('onEncoderJobProgress', $._PPP_.onEncoderJobProgress); + app.encoder.bind('onEncoderJobQueued', $._PPP_.onEncoderJobQueued); + app.encoder.bind('onEncoderJobCanceled', $._PPP_.onEncoderJobCanceled); + + var projRoot = app.project.rootItem.children; + + if (projRoot.numItems) { + var firstProjectItem = app.project.rootItem.children[0]; + if (firstProjectItem) { + app.encoder.launchEncoder(); // This can take a while; let's get the ball rolling. + + var fileOutputPath = Folder.selectDialog('Choose the output directory'); + if (fileOutputPath) { + var regExp = new RegExp('[.]'); + var outputName = firstProjectItem.name.search(regExp); + if (outputName == -1) { + outputName = firstProjectItem.name.length; + } + var outFileName = firstProjectItem.name.substr(0, outputName); + outFileName = outFileName.replace('/', '-'); + var completeOutputPath = + fileOutputPath.fsName + $._PPP_.getSep() + outFileName + '.mxf'; + var removeFromQueue = 1; + var rangeToEncode = app.encoder.ENCODE_IN_TO_OUT; + app.encoder.encodeProjectItem( + firstProjectItem, + completeOutputPath, + outputPresetPath, + rangeToEncode, + removeFromQueue + ); + app.encoder.startBatch(); + } + } else { + $._PPP_.updateEventPanel('No project items found.'); + } + } else { + $._PPP_.updateEventPanel('Project is empty.'); + } + }, + + transcodeExternal: function(outputPresetPath) { + app.encoder.launchEncoder(); + var filterString = ''; + if (Folder.fs === 'Windows') { + filterString = 'All files:*.*'; + } + var fileToTranscode = File.openDialog( + 'Choose file to open.', + filterString, + false + ); + if (fileToTranscode) { + var fileOutputPath = Folder.selectDialog('Choose the output directory'); + if (fileOutputPath) { + var srcInPoint = new Time(); + srcInPoint.seconds = 1.0; // encode start time at 1s (optional--if omitted, encode entire file) + var srcOutPoint = new Time(); + srcOutPoint.seconds = 3.0; // encode stop time at 3s (optional--if omitted, encode entire file) + var removeFromQueue = 0; + + var result = app.encoder.encodeFile( + fileToTranscode.fsName, + fileOutputPath.fsName, + outputPresetPath, + removeFromQueue, + srcInPoint, + srcOutPoint + ); + } + } + }, + + render: function(outputPresetPath) { + app.enableQE(); + var activeSequence = qe.project.getActiveSequence(); // we use a QE DOM function, to determine the output extension. + if (activeSequence) { + var ameInstalled = false; + var ameStatus = BridgeTalk.getStatus('ame'); + if (ameStatus == 'ISNOTINSTALLED') { + $._PPP_.updateEventPanel('AME is not installed.'); + } else if (ameInstalled) { + if (ameStatus == 'ISNOTRUNNING') { + app.encoder.launchEncoder(); // This can take a while; let's get the ball rolling. + } + var timeSecs = activeSequence.CTI.secs; // Just for reference, here's how to access the CTI + var timeFrames = activeSequence.CTI.frames; // (Current Time Indicator), for the active sequence. + var timeTicks = activeSequence.CTI.ticks; + var timeString = activeSequence.CTI.timecode; + + var seqInPoint = app.project.activeSequence.getInPoint(); // new in 9.0 + var seqOutPoint = app.project.activeSequence.getOutPoint(); // new in 9.0 + + var seqInPointAsTime = app.project.activeSequence.getInPointAsTime(); // new in 12.0 + var seqOutPointAsTime = app.project.activeSequence.getOutPointAsTime(); // new in 12.0 + + var projPath = new File(app.project.path); + var outputPath = Folder.selectDialog('Choose the output directory'); + + if (outputPath && projPath.exists) { + var outPreset = new File(outputPresetPath); + if (outPreset.exists === true) { + var outputFormatExtension = activeSequence.getExportFileExtension( + outPreset.fsName + ); + if (outputFormatExtension) { + var outputFilename = + activeSequence.name + '.' + outputFormatExtension; + + var fullPathToFile = + outputPath.fsName + + $._PPP_.getSep() + + activeSequence.name + + '.' + + outputFormatExtension; + + var outFileTest = new File(fullPathToFile); + + if (outFileTest.exists) { + var destroyExisting = confirm( + 'A file with that name already exists; overwrite?', + false, + 'Are you sure...?' + ); + if (destroyExisting) { + outFileTest.remove(); + outFileTest.close(); + } + } + + app.encoder.bind( + 'onEncoderJobComplete', + $._PPP_.onEncoderJobComplete + ); + app.encoder.bind('onEncoderJobError', $._PPP_.onEncoderJobError); + app.encoder.bind( + 'onEncoderJobProgress', + $._PPP_.onEncoderJobProgress + ); + app.encoder.bind( + 'onEncoderJobQueued', + $._PPP_.onEncoderJobQueued + ); + app.encoder.bind( + 'onEncoderJobCanceled', + $._PPP_.onEncoderJobCanceled + ); + + app.encoder.setSidecarXMPEnabled(0); // use these 0 or 1 settings to disable some/all metadata creation. + app.encoder.setEmbeddedXMPEnabled(0); + + /* + For reference, here's how to export from within PPro (blocking further user interaction). + + var seq = app.project.activeSequence; + + if (seq) { + seq.exportAsMediaDirect(fullPathToFile, + outPreset.fsName, + app.encoder.ENCODE_WORKAREA); + + Bonus: Here's how to compute a sequence's duration, in ticks. 254016000000 ticks/second. + var sequenceDuration = app.project.activeSequence.end - app.project.activeSequence.zeroPoint; + } + */ + + var removeFromQueueUponSuccess = 1; + var jobID = app.encoder.encodeSequence( + app.project.activeSequence, + fullPathToFile, + outPreset.fsName, + app.encoder.ENCODE_WORKAREA, + removeFromQueueUponSuccess + ); + + $._PPP_.updateEventPanel('jobID = ' + jobID); + outPreset.close(); + } + } else { + $._PPP_.updateEventPanel('Could not find output preset.'); + } + } else { + $._PPP_.updateEventPanel('Could not find/create output path.'); + } + projPath.close(); + } + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + saveProjectCopy: function() { + var sessionCounter = 1; + var originalPath = app.project.path; + var outputPath = Folder.selectDialog('Choose the output directory'); + + if (outputPath) { + var absPath = outputPath.fsName; + var outputName = String(app.project.name); + var array = outputName.split('.', 2); + + outputName = array[0] + sessionCounter + '.' + array[1]; + sessionCounter++; + + var fullOutPath = absPath + $._PPP_.getSep() + outputName; + + app.project.saveAs(fullOutPath); + + for (var a = 0; a < app.projects.numProjects; a++) { + var currentProject = app.projects[a]; + if (currentProject.path === fullOutPath) { + app.openDocument(originalPath, true, false, false); // Why first? So we don't frighten the user by making PPro's window disappear. :) + currentProject.closeDocument(); + } + } + } else { + $._PPP_.updateEventPanel('No output path chosen.'); + } + }, + + mungeXMP: function() { + var projectItem = app.project.rootItem.children[0]; // assumes first item is footage. + if (projectItem) { + if (ExternalObject.AdobeXMPScript === undefined) { + ExternalObject.AdobeXMPScript = new ExternalObject( + 'lib:AdobeXMPScript' + ); + } + if (ExternalObject.AdobeXMPScript !== undefined) { + // safety-conscious! + + var xmpBlob = projectItem.getXMPMetadata(); + var xmp = new XMPMeta(xmpBlob); + var oldSceneVal = ''; + var oldDMCreatorVal = ''; + + if (xmp.doesPropertyExist(XMPConst.NS_DM, 'scene') === true) { + var myScene = xmp.getProperty(XMPConst.NS_DM, 'scene'); + oldSceneVal = myScene.value; + } + + if (xmp.doesPropertyExist(XMPConst.NS_DM, 'creator') === true) { + var myCreator = xmp.getProperty(XMPConst.NS_DM, 'creator'); + oldDMCreatorVal = myCreator.value; + } + + // Regardless of whether there WAS scene or creator data, set scene and creator data. + + xmp.setProperty( + XMPConst.NS_DM, + 'scene', + oldSceneVal + ' Added by PProPanel sample!' + ); + xmp.setProperty( + XMPConst.NS_DM, + 'creator', + oldDMCreatorVal + ' Added by PProPanel sample!' + ); + + // That was the NS_DM creator; here's the NS_DC creator. + + var creatorProp = 'creator'; + var containsDMCreatorValue = xmp.doesPropertyExist( + XMPConst.NS_DC, + creatorProp + ); + var numCreatorValuesPresent = xmp.countArrayItems( + XMPConst.NS_DC, + creatorProp + ); + var CreatorsSeparatedBy4PoundSigns = ''; + + if (numCreatorValuesPresent > 0) { + for (var z = 0; z < numCreatorValuesPresent; z++) { + CreatorsSeparatedBy4PoundSigns = + CreatorsSeparatedBy4PoundSigns + + xmp.getArrayItem(XMPConst.NS_DC, creatorProp, z + 1); + CreatorsSeparatedBy4PoundSigns = + CreatorsSeparatedBy4PoundSigns + '####'; + } + $._PPP_.updateEventPanel(CreatorsSeparatedBy4PoundSigns); + + if ( + confirm('Replace previous?', false, 'Replace existing Creator?') + ) { + xmp.deleteProperty(XMPConst.NS_DC, 'creator'); + } + xmp.appendArrayItem( + XMPConst.NS_DC, // If no values exist, appendArrayItem will create a value. + creatorProp, + numCreatorValuesPresent + ' creator values were already present.', + null, + XMPConst.ARRAY_IS_ORDERED + ); + } else { + xmp.appendArrayItem( + XMPConst.NS_DC, + creatorProp, + 'PProPanel wrote the first value into NS_DC creator field.', + null, + XMPConst.ARRAY_IS_ORDERED + ); + } + var xmpAsString = xmp.serialize(); // either way, serialize and write XMP. + projectItem.setXMPMetadata(xmpAsString); + } + } else { + $._PPP_.updateEventPanel('Project item required.'); + } + }, + + getProductionByName: function(nameToGet) { + var production; + var allProductions = app.anywhere.listProductions(); + for (var i = 0; i < allProductions.numProductions; i++) { + var currentProduction = allProductions[i]; + if (currentProduction.name === nameToGet) { + production = currentProduction; + } + } + return production; + }, + + pokeAnywhere: function() { + var token = app.anywhere.getAuthenticationToken(); + var productionList = app.anywhere.listProductions(); + var isProductionOpen = app.anywhere.isProductionOpen(); + if (isProductionOpen === true) { + var sessionURL = app.anywhere.getCurrentEditingSessionURL(); + var selectionURL = app.anywhere.getCurrentEditingSessionSelectionURL(); + var activeSequenceURL = app.anywhere.getCurrentEditingSessionActiveSequenceURL(); + var theOneIAskedFor = $._PPP_.getProductionByName('test'); + if (theOneIAskedFor) { + var out = theOneIAskedFor.name + ', ' + theOneIAskedFor.description; + $._PPP_.updateEventPanel('Found: ' + out); // todo: put useful code here. + } + } else { + $._PPP_.updateEventPanel('No Production open.'); + } + }, + + dumpOMF: function() { + var activeSequence = app.project.activeSequence; + if (activeSequence) { + var outputPath = Folder.selectDialog('Choose the output directory'); + if (outputPath) { + var absPath = outputPath.fsName; + var outputName = String(activeSequence.name) + '.omf'; + var fullOutPathWithName = absPath + $._PPP_.getSep() + outputName; + + app.project.exportOMF( + app.project.activeSequence, // sequence + fullOutPathWithName, // output file path + 'OMFTitle', // OMF title + 48000, // sample rate (48000 or 96000) + 16, // bits per sample (16 or 24) + 1, // audio encapsulated flag (1 : yes or 0 : no) + 0, // audio file format (0 : AIFF or 1 : WAV) + 0, // trim audio files (0 : no or 1 : yes) + 0, // handle frames (if trim is 1, handle frames from 0 to 1000) + 0 + ); // include pan flag (0 : no or 1 : yes) + } + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + addClipMarkers: function() { + if (app.project.rootItem.children.numItems > 0) { + var projectItem = app.project.rootItem.children[0]; // assumes first item is footage. + if (projectItem) { + if ( + projectItem.type == ProjectItemType.CLIP || + projectItem.type == ProjectItemType.FILE + ) { + var markers = projectItem.getMarkers(); + if (markers) { + var numMarkers = markers.numMarkers; + var newMarker = markers.createMarker(12.345); + var guid = newMarker.guid; // new in 11.1 + newMarker.name = 'Marker created by PProPanel.'; + newMarker.comments = + 'Here are some comments, inserted by PProPanel.'; + var tempTime = new Time(); + tempTime.seconds = 15.6789; + newMarker.end = tempTime; + + //default marker type == comment. To change marker type, call one of these: + + // newMarker.setTypeAsChapter(); + // newMarker.setTypeAsWebLink(); + // newMarker.setTypeAsSegmentation(); + // newMarker.setTypeAsComment(); + } + } else { + $._PPP_.updateEventPanel('Can only add markers to footage items.'); + } + } else { + $._PPP_.updateEventPanel('Could not find first projectItem.'); + } + } else { + $._PPP_.updateEventPanel('Project is empty.'); + } + }, + + modifyProjectMetadata: function() { + var kPProPrivateProjectMetadataURI = + 'http://ns.adobe.com/premierePrivateProjectMetaData/1.0/'; + var nameField = 'Column.Intrinsic.Name'; + var tapeName = 'Column.Intrinsic.TapeName'; + var logNote = 'Column.Intrinsic.LogNote'; + var newField = 'ExampleFieldName'; + var desc = 'Column.PropertyText.Description'; + + if (app.isDocumentOpen()) { + var projectItem = app.project.rootItem.children[0]; // just grabs first projectItem. + if (projectItem) { + if (ExternalObject.AdobeXMPScript === undefined) { + ExternalObject.AdobeXMPScript = new ExternalObject( + 'lib:AdobeXMPScript' + ); + } + if (ExternalObject.AdobeXMPScript !== undefined) { + // safety-conscious! + var projectMetadata = projectItem.getProjectMetadata(); + var successfullyAdded = app.project.addPropertyToProjectMetadataSchema( + newField, + 'ExampleFieldLabel', + 2 + ); + var xmp = new XMPMeta(projectMetadata); + var obj = xmp.dumpObject(); + var foundLogNote = xmp.doesPropertyExist( + kPProPrivateProjectMetadataURI, + logNote + ); + var oldLogValue = ''; + var appendThis = 'This log note inserted by PProPanel.'; + var appendTextWasActuallyNew = false; + + if (foundLogNote) { + var oldLogNote = xmp.getProperty( + kPProPrivateProjectMetadataURI, + logNote + ); + if (oldLogNote) { + oldLogValue = oldLogNote.value; + } + } + xmp.setProperty( + kPProPrivateProjectMetadataURI, + tapeName, + '***TAPENAME***' + ); + xmp.setProperty( + kPProPrivateProjectMetadataURI, + desc, + '***DESCRIPTION***' + ); + xmp.setProperty( + kPProPrivateProjectMetadataURI, + nameField, + '***NEWNAME***' + ); + xmp.setProperty( + kPProPrivateProjectMetadataURI, + newField, + 'PProPanel set this, using addPropertyToProjectMetadataSchema().' + ); + + var array = []; + array[0] = tapeName; + array[1] = desc; + array[2] = nameField; + array[3] = newField; + + var concatenatedLogNotes = ''; + + if (oldLogValue != appendThis) { + // if that value is not exactly what we were going to add + if (oldLogValue.length > 0) { + // if we have a valid value + concatenatedLogNotes += + 'Previous log notes: ' + oldLogValue + ' |||| '; + } + concatenatedLogNotes += appendThis; + xmp.setProperty( + kPProPrivateProjectMetadataURI, + logNote, + concatenatedLogNotes + ); + array[4] = logNote; + } + var str = xmp.serialize(); + projectItem.setProjectMetadata(str, array); + + // test: is it in there? + + var newblob = projectItem.getProjectMetadata(); + var newXMP = new XMPMeta(newblob); + var foundYet = newXMP.doesPropertyExist( + kPProPrivateProjectMetadataURI, + newField + ); + + if (foundYet) { + $._PPP_.updateEventPanel( + 'PProPanel successfully added a field to the project metadata schema, and set a value for it.' + ); + } + } + } else { + $._PPP_.updateEventPanel('No project items found.'); + } + } + }, + + updatePAR: function() { + var item = app.project.rootItem.children[0]; + if (item) { + if ( + item.type == ProjectItemType.FILE || + item.type == ProjectItemType.CLIP + ) { + // If there is an item, and it's either a clip or file... + item.setOverridePixelAspectRatio(185, 100); // anamorphic is BACK! ;) + } else { + $._PPP_.updateEventPanel( + 'You cannot override the PAR of bins or sequences.' + ); + } + } else { + $._PPP_.updateEventPanel('No project items found.'); + } + }, + + getnumAEProjectItems: function() { + var bt = new BridgeTalk(); + bt.target = 'aftereffects'; + bt.body = + 'alert("Items in AE project: " + app.project.rootFolder.numItems);app.quit();'; + bt.send(); + }, + + updateEventPanel: function(message) { + app.setSDKEventMessage(message, 'info'); + //app.setSDKEventMessage('Here is some information.', 'info'); + //app.setSDKEventMessage('Here is a warning.', 'warning'); + //app.setSDKEventMessage('Here is an error.', 'error'); Very annoying; use sparingly. + }, + + walkAllBinsDumpingXMP: function(parentItem, outPath) { + for (var j = 0; j < parentItem.children.numItems; j++) { + var currentChild = parentItem.children[j]; + if (currentChild) { + if (currentChild.type === ProjectItemType.BIN) { + $._PPP_.walkAllBinsDumpingXMP(currentChild, outPath); // warning; recursion! + } else { + $._PPP_.dumpProjectItemXMP(currentChild, outPath); + } + } + } + }, + + walkAllBinsUpdatingPaths: function(parentItem, outPath) { + for (var j = 0; j < parentItem.children.numItems; j++) { + var currentChild = parentItem.children[j]; + if (currentChild) { + if (currentChild.type === ProjectItemType.BIN) { + $._PPP_.walkAllBinsUpdatingPaths(currentChild, outPath); // warning; recursion! + } else { + $._PPP_.updateProjectItemPath(currentChild, outPath); + } + } + } + }, + + searchBinForProjItemByName: function(i, containingBin, nameToFind) { + for (var j = i; j < containingBin.children.numItems; j++) { + var currentChild = containingBin.children[j]; + if (currentChild) { + if (currentChild.type === ProjectItemType.BIN) { + return $._PPP_.searchBinForProjItemByName( + j, + currentChild, + nameToFind + ); // warning; recursion! + } else { + if (currentChild.name === nameToFind) { + return currentChild; + } else { + currentChild = currentChild.children[j + 1]; + if (currentChild) { + return $._PPP_.searchBinForProjItemByName( + 0, + currentChild, + nameToFind + ); + } + } + } + } + } + }, + + dumpProjectItemXMP: function(projectItem, outPath) { + var xmpBlob = projectItem.getXMPMetadata(); + var outFileName = projectItem.name + '.xmp'; + var completeOutputPath = outPath + $._PPP_.getSep() + outFileName; + var outFile = new File(completeOutputPath); + var isThisASequence = projectItem.isSequence(); + + if (outFile) { + outFile.encoding = 'UTF8'; + outFile.open('w', 'TEXT', '????'); + outFile.write(xmpBlob.toString()); + outFile.close(); + } + }, + + addSubClip: function() { + var startTime = new Time(); + startTime.seconds = 0.0; + var endTime = new Time(); + endTime.seconds = 3.21; + var hasHardBoundaries = 0; + var sessionCounter = 1; + var takeVideo = 1; // optional, defaults to 1 + var takeAudio = 1; // optional, defaults to 1 + var projectItem = app.project.rootItem.children[0]; // just grabs the first item + if (projectItem) { + if ( + projectItem.type === ProjectItemType.CLIP || + projectItem.type === ProjectItemType.FILE + ) { + var newSubClipName = prompt( + 'Name of subclip?', + projectItem.name + '_' + sessionCounter, + 'Name your subclip' + ); + if (newSubClipName) { + var newSubClip = projectItem.createSubClip( + newSubClipName, + startTime, + endTime, + hasHardBoundaries, + takeVideo, + takeAudio + ); + if (newSubClip) { + var newStartTime = new Time(); + newStartTime.seconds = 12.345; + newSubClip.setStartTime(newStartTime); + } + } else { + $._PPP_.updateEventPanel('No name provided for sub-clip.'); + } + } else { + $._PPP_.updateEventPanel( + 'Could not sub-clip ' + projectItem.name + '.' + ); + } + } else { + $._PPP_.updateEventPanel('No project item found.'); + } + }, + + dumpXMPFromAllProjectItems: function() { + var numItemsInRoot = app.project.rootItem.children.numItems; + if (numItemsInRoot > 0) { + var outPath = Folder.selectDialog('Choose the output directory'); + if (outPath) { + for (var i = 0; i < numItemsInRoot; i++) { + var currentItem = app.project.rootItem.children[i]; + if (currentItem) { + if (currentItem.type == ProjectItemType.BIN) { + $._PPP_.walkAllBinsDumpingXMP(currentItem, outPath.fsName); + } else { + $._PPP_.dumpProjectItemXMP(currentItem, outPath.fsName); + } + } + } + } + } else { + $._PPP_.updateEventPanel('No project items found.'); + } + }, + + exportAAF: function() { + var sessionCounter = 1; + if (app.project.activeSequence) { + var outputPath = Folder.selectDialog('Choose the output directory'); + if (outputPath) { + var absPath = outputPath.fsName; + var outputName = String(app.project.name); + var array = outputName.split('.', 2); + outputName = array[0] + sessionCounter + '.' + array[1]; + var fullOutPath = absPath + $._PPP_.getSep() + outputName + '.aaf'; + //var optionalPathToOutputPreset = null; New in 11.0.0, you can specify an output preset. + + app.project.exportAAF( + app.project.activeSequence, // which sequence + fullOutPath, // output path + 1, // mix down video? + 0, // explode to mono? + 96000, // sample rate + 16, // bits per sample + 0, // embed audio? + 0, // audio file format? 0 = aiff, 1 = wav + 0, // number of 'handle' frames + 0 + /* + optionalPathToOutputPreset*/ + ); // optional; .epr file to use + sessionCounter++; + } else { + $._PPP_.updateEventPanel('Couldn\'t create AAF output.'); + } + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + setScratchDisk: function() { + var scratchPath = Folder.selectDialog('Choose new scratch disk directory'); + if (scratchPath && scratchPath.exists) { + app.setScratchDiskPath( + scratchPath.fsName, + ScratchDiskType.FirstAutoSaveFolder + ); // see ScratchDiskType object, in ESTK. + } + }, + + getProjectProxySetting: function() { + var returnVal = ''; + if (app.project) { + var returnVal = 'No sequence detected in ' + app.project.name + '.'; + if (app.getEnableProxies()) { + returnVal = 'true'; + } else { + returnVal = 'false'; + } + } else { + returnVal = 'No project available.'; + } + return returnVal; + }, + + toggleProxyState: function() { + var update = 'Proxies for ' + app.project.name + ' turned '; + if (app.getEnableProxies()) { + app.setEnableProxies(0); + update = update + 'OFF.'; + } else { + app.setEnableProxies(1); + update = update + 'ON.'; + } + $._PPP_.updateEventPanel(update); + }, + + setProxiesON: function() { + var firstProjectItem = app.project.rootItem.children[0]; + if (firstProjectItem) { + if (firstProjectItem.canProxy()) { + var shouldAttachProxy = true; + if (firstProjectItem.hasProxy()) { + shouldAttachProxy = confirm( + firstProjectItem.name + + ' already has an assigned proxy. Re-assign anyway?', + false, + 'Are you sure...?' + ); + } + if (shouldAttachProxy) { + var filterString = ''; + if (Folder.fs === 'Windows') { + filterString = 'All files:*.*'; + } + var proxyPath = File.openDialog( + 'Choose proxy for ' + firstProjectItem.name + ':', + filterString, + false + ); + if (proxyPath.exists) { + firstProjectItem.attachProxy(proxyPath.fsName, 0); + } else { + $._PPP_.updateEventPanel( + 'Could not attach proxy from ' + proxyPath + '.' + ); + } + } + } else { + $._PPP_.updateEventPanel( + 'Cannot attach a proxy to ' + firstProjectItem.name + '.' + ); + } + } else { + $._PPP_.updateEventPanel('No project item available.'); + } + }, + + clearCache: function() { + app.enableQE(); + qe.project.deletePreviewFiles(MediaType_ANY); + $._PPP_.updateEventPanel('All video and audio preview files deleted.'); + }, + + randomizeSequenceSelection: function() { + var sequence = app.project.activeSequence; + if (sequence) { + var trackGroups = [sequence.audioTracks, sequence.videoTracks]; + var trackGroupNames = ['audioTracks', 'videoTracks']; + var updateUI = true; + + for (var groupIndex = 0; groupIndex < 2; groupIndex++) { + $._PPP_.updateEventPanel(trackGroupNames[groupIndex]); + var group = trackGroups[groupIndex]; + for (var trackIndex = 0; trackIndex < group.numTracks; trackIndex++) { + var track = group[trackIndex]; + var clips = track.clips; + var transitions = track.transitions; + var beforeSelected; + var afterSelected; + var initialSelectState; + + $._PPP_.updateEventPanel( + 'track : ' + + trackIndex + + ' clip count: ' + + clips.numItems + + ' transition count: ' + + transitions.numItems + ); + + for (var clipIndex = 0; clipIndex < clips.numItems; clipIndex++) { + var clip = clips[clipIndex]; + var name = + clip.projectItem === undefined ? '' : clip.projectItem.name; + initialSelectState = clip.isSelected(); + + // randomly select clips + clip.setSelected(Math.random() > 0.5, updateUI); + + if (clip.isAdjustmentLayer()) { + // new in 13.0 + $._PPP_.updateEventPanel( + 'Clip named "' + clip.name + '" is an adjustment layer.' + ); + } + + // Note; there's no good place to exercise this code yet, but + // I wanted to provide example usage. + + var allClipsInThisSequenceFromSameSource = clip.getLinkedItems(); + + if (allClipsInThisSequenceFromSameSource) { + $._PPP_.updateEventPanel( + 'Found ' + + allClipsInThisSequenceFromSameSource.numItems + + ' clips from ' + + clip.projectItem.name + + ', in this sequence.' + ); + } + beforeSelected = initialSelectState ? 'Y' : 'N'; + afterSelected = clip.isSelected() ? 'Y' : 'N'; + $._PPP_.updateEventPanel( + 'clip : ' + + clipIndex + + ' ' + + name + + ' ' + + beforeSelected + + ' -> ' + + afterSelected + ); + } + + for (var tni = 0; tni < transitions.numItems; ++tni) { + var transition = transitions[tni]; + var doIt = false; + initialSelectState = transition.isSelected(); + // randomly select transitions + if (Math.random() > 0.5) { + doIt = true; + } + transition.setSelected(doIt, updateUI); + beforeSelected = initialSelectState ? 'Y' : 'N'; + afterSelected = transition.isSelected() ? 'Y' : 'N'; + $._PPP_.updateEventPanel( + 'transition: ' + + tni + + ' ' + + beforeSelected + + ' -> ' + + afterSelected + ); + } + } + } + } else { + $._PPP_.updateEventPanel('no active sequence.'); + } + }, + + // Define a couple of callback functions, for AME to use during render. + + onEncoderJobComplete: function(jobID, outputFilePath) { + var eoName; + + if (Folder.fs == 'Macintosh') { + eoName = 'PlugPlugExternalObject'; + } else { + eoName = 'PlugPlugExternalObject.dll'; + } + + var mylib = new ExternalObject('lib:' + eoName); + + var suffixAddedByPPro = '_1'; // You should really test for any suffix. + var withoutExtension = outputFilePath.slice(0, -4); // trusting 3 char extension + var lastIndex = outputFilePath.lastIndexOf('.'); + var extension = outputFilePath.substr(lastIndex + 1); + + if (outputFilePath.indexOf(suffixAddedByPPro)) { + $._PPP_.updateEventPanel( + ' Output filename was changed: the output preset name may have been added, or there may have been an existing file with that name. This would be a good place to deal with such occurrences.' + ); + } + + var eventObj = new CSXSEvent(); + eventObj.type = 'com.adobe.csxs.events.PProPanelRenderEvent'; + eventObj.data = 'Rendered Job ' + jobID + ', to ' + outputFilePath + '.'; + eventObj.dispatch(); + }, + + onEncoderJobError: function(jobID, errorMessage) { + var eoName = ''; + if (Folder.fs === 'Macintosh') { + eoName = 'PlugPlugExternalObject'; + } else { + eoName = 'PlugPlugExternalObject.dll'; + } + var eventObj = new CSXSEvent(); + eventObj.type = 'com.adobe.csxs.events.PProPanelRenderEvent'; + eventObj.data = 'Job ' + jobID + ' failed, due to ' + errorMessage + '.'; + eventObj.dispatch(); + }, + + onEncoderJobProgress: function(jobID, progress) { + $._PPP_.updateEventPanel( + 'onEncoderJobProgress called. jobID = ' + + jobID + + '. progress = ' + + progress + + '.' + ); + }, + + onEncoderJobQueued: function(jobID) { + $._PPP_.updateEventPanel('jobID ' + jobID + 'successfully queued.'); + app.encoder.startBatch(); + }, + + onEncoderJobCanceled: function(jobID) { + $._PPP_.updateEventPanel( + 'OnEncoderJobCanceled called. jobID = ' + jobID + '.' + ); + }, + + onPlayWithKeyframes: function() { + var seq = app.project.activeSequence; + if (seq) { + var firstVideoTrack = seq.videoTracks[0]; + if (firstVideoTrack) { + var firstClip = firstVideoTrack.clips[0]; + if (firstClip) { + var clipComponents = firstClip.components; + if (clipComponents) { + for (var i = 0; i < clipComponents.numItems; ++i) { + $._PPP_.updateEventPanel( + 'component ' + + i + + ' = ' + + clipComponents[i].matchName + + ' : ' + + clipComponents[i].displayName + ); + } + if (clipComponents.numItems > 2) { + // 0 = clip + // 1 = Opacity + // N effects, then... + // Shape layer (new in 12.0) + + var updateUI = true; + var blur = clipComponents[2]; // Assume Gaussian Blur is the first effect applied to the clip. + if (blur) { + var blurProps = blur.properties; + if (blurProps) { + for (var j = 0; j < blurProps.numItems; ++j) { + $._PPP_.updateEventPanel( + 'param ' + j + ' = ' + blurProps[j].displayName + ); + } + var blurriness = blurProps[0]; + + /* Sample code showing how to get and set the values of a color parameter. + + var colorToChange = change_colorProps[N]; // where 'N' is the index of the effect with a color param. + + var colorVal = colorToChange.getColorValue(); + + var alpha = colorVal[0]; + var red = colorVal[1]; + var blue = colorVal[2]; + var green = colorVal[3]; + + colorToChange.setColorValue(255, 33, 222, 111); // a, r, g, b + + */ + + if (blurriness) { + if (!blurriness.isTimeVarying()) { + blurriness.setTimeVarying(true); + } + for (var k = 0; k < 20; ++k) { + updateUI = k == 9; // Decide how often to update PPro's UI + blurriness.addKey(k); + var blurVal = Math.sin((3.14159 * i) / 5) * 20 + 25; + blurriness.setValueAtKey(k, blurVal, updateUI); + } + } + + var repeatEdgePixels = blurProps[2]; + if (repeatEdgePixels) { + if (!repeatEdgePixels.getValue()) { + updateUI = true; + repeatEdgePixels.setValue(true, updateUI); + } + } + + // look for keyframe nearest to 4s with 1/10 second tolerance + + var keyFrameTime = blurriness.findNearestKey(4.0, 0.1); + if (keyFrameTime !== undefined) { + $._PPP_.updateEventPanel( + 'Found keyframe = ' + keyFrameTime.seconds + ); + } else { + $._PPP_.updateEventPanel('Keyframe not found.'); + } + + // scan keyframes, forward + + keyFrameTime = blurriness.findNearestKey(0.0, 0.1); + var lastKeyFrameTime = keyFrameTime; + while (keyFrameTime !== undefined) { + $._PPP_.updateEventPanel( + 'keyframe @ ' + keyFrameTime.seconds + ); + lastKeyFrameTime = keyFrameTime; + keyFrameTime = blurriness.findNextKey(keyFrameTime); + } + + // scan keyframes, backward + keyFrameTime = lastKeyFrameTime; + while (keyFrameTime !== undefined) { + $._PPP_.updateEventPanel( + 'keyframe @ ' + keyFrameTime.seconds + ); + lastKeyFrameTime = keyFrameTime; + keyFrameTime = blurriness.findPreviousKey(keyFrameTime); + } + + var blurKeyframesArray = blurriness.getKeys(); // get all keyframes + if (blurKeyframesArray) { + $._PPP_.updateEventPanel( + blurKeyframesArray.length + ' keyframes found' + ); + } + + blurriness.removeKey(19); // remove keyframe at 19s + + var shouldUpdateUI = true; + blurriness.removeKeyRange(0, 5, shouldUpdateUI); // remove keyframes in range from 0s to 5s + } + } else { + $._PPP_.updateEventPanel( + 'Please apply the Gaussian Blur effect to the first clip in the first video track of the active sequence.' + ); + } + } + } + } + } + } else { + $._PPP_.updateEventPanel('no active sequence.'); + } + }, + + extractFileNameFromPath: function(fullPath) { + var lastDot = fullPath.lastIndexOf('.'); + var lastSep = fullPath.lastIndexOf('/'); + if (lastDot > -1) { + return fullPath.substr(lastSep + 1, fullPath.length - (lastDot + 1)); + } else { + return fullPath; + } + }, + + onProxyTranscodeJobComplete: function(jobID, outputFilePath) { + var suffixAddedByPPro = '_1'; // You should really test for any suffix. + var withoutExtension = outputFilePath.slice(0, -4); // trusting 3 char extension + var lastIndex = outputFilePath.lastIndexOf('.'); + var extension = outputFilePath.substr(lastIndex + 1); + var wrapper = []; + wrapper[0] = outputFilePath; + var nameToFind = 'Proxies generated by PProPanel'; + var targetBin = $._PPP_.getPPPInsertionBin(); + if (targetBin) { + app.project.importFiles(wrapper, true, null, false); + } + }, + + onProxyTranscodeJobError: function(jobID, errorMessage) { + $._PPP_.updateEventPanel(errorMessage); + }, + + onProxyTranscodeJobQueued: function(jobID) { + app.encoder.startBatch(); + }, + + ingestFiles: function(outputPresetPath) { + app.encoder.bind( + 'onEncoderJobComplete', + $._PPP_.onProxyTranscodeJobComplete + ); + app.encoder.bind('onEncoderJobError', $._PPP_.onProxyTranscodeJobError); + app.encoder.bind('onEncoderJobQueued', $._PPP_.onProxyTranscodeJobQueued); + app.encoder.bind('onEncoderJobCanceled', $._PPP_.onEncoderJobCanceled); + + if (app.project) { + var filterString = ''; + if (Folder.fs === 'Windows') { + filterString = 'All files:*.*'; + } + var fileOrFilesToImport = File.openDialog( + 'Choose full resolution files to import', // title + filterString, // filter available files? + true + ); // allow multiple fiels to be selected? + if (fileOrFilesToImport) { + var nameToFind = 'Proxies generated by PProPanel'; + var targetBin = $._PPP_.searchForBinWithName(nameToFind); + if (targetBin === 0) { + // If panel can't find the target bin, it creates it. + app.project.rootItem.createBin(nameToFind); + targetBin = $._PPP_.searchForBinWithName(nameToFind); + } + if (targetBin) { + targetBin.select(); + var importThese = []; // We have an array of File objects; importFiles() takes an array of paths. + if (importThese) { + for (var i = 0; i < fileOrFilesToImport.length; i++) { + importThese[i] = fileOrFilesToImport[i].fsName; + var justFileName = $._PPP_.extractFileNameFromPath( + importThese[i] + ); + var suffix = '_PROXY.mp4'; + var containingPath = fileOrFilesToImport[i].parent.fsName; + var completeProxyPath = + containingPath + $._PPP_.getSep() + justFileName + suffix; + + var jobID = app.encoder.encodeFile( + fileOrFilesToImport[i].fsName, + completeProxyPath, + outputPresetPath, + 0 + ); + } + + app.project.importFiles( + importThese, + true, // suppress warnings + targetBin, + false + ); // import as numbered stills + } + } else { + $._PPP_.updateEventPanel('Could not find or create target bin.'); + } + } else { + $._PPP_.updateEventPanel('No files to import.'); + } + } else { + $._PPP_.updateEventPanel('No project found.'); + } + }, + + insertOrAppend: function() { + var seq = app.project.activeSequence; + if (seq) { + var first = app.project.rootItem.children[0]; + if (first) { + if (!first.isSequence()) { + if (first.type !== ProjectItemType.BIN) { + var numVTracks = seq.videoTracks.numTracks; + var targetVTrack = seq.videoTracks[numVTracks - 1]; + if (targetVTrack) { + // If there are already clips in this track, append this one to the end. Otherwise, insert at start time. + if (targetVTrack.clips.numItems > 0) { + var lastClip = + targetVTrack.clips[targetVTrack.clips.numItems - 1]; + if (lastClip) { + targetVTrack.insertClip(first, lastClip.end.seconds); + } + } else { + var timeAtZero = new Time(); + targetVTrack.insertClip(first, timeAtZero.seconds); + // New in 13.1; using the new linkSelection/unlinkSelection calls, + // panels can remove just the audio (or video) of a given clip. + var newlyAddedClip = + targetVTrack.clips[targetVTrack.clips.numItems - 1]; + if (newlyAddedClip) { + newlyAddedClip.setSelected(true, true); + seq.unlinkSelection(); + newlyAddedClip.remove(true, true); + seq.linkSelection(); + } + } + } else { + $._PPP_.updateEventPanel('Could not find first video track.'); + } + } else { + $._PPP_.updateEventPanel(first.name + ' is a bin.'); + } + } else { + $._PPP_.updateEventPanel(first.name + ' is a sequence.'); + } + } else { + $._PPP_.updateEventPanel('Couldn\'t locate first projectItem.'); + } + } else { + $._PPP_.updateEventPanel('no active sequence.'); + } + }, + + overWrite: function() { + var seq = app.project.activeSequence; + if (seq) { + var first = app.project.rootItem.children[0]; + if (first) { + var vTrack1 = seq.videoTracks[0]; + if (vTrack1) { + var now = seq.getPlayerPosition(); + vTrack1.overwriteClip(first, now.seconds); + } else { + $._PPP_.updateEventPanel('Could not find first video track.'); + } + } else { + $._PPP_.updateEventPanel('Couldn\'t locate first projectItem.'); + } + } else { + $._PPP_.updateEventPanel('no active sequence.'); + } + }, + + closeFrontSourceClip: function() { + app.sourceMonitor.closeClip(); + }, + + closeAllClipsInSourceMonitor: function() { + app.sourceMonitor.closeAllClips(); + }, + + changeLabel: function() { + var first = app.project.rootItem.children[0]; + if (first) { + var currentLabel = first.getColorLabel(); + var newLabel = currentLabel + 1; // 4 = Cerulean. 0 = Violet, 15 = Yellow. + if (newLabel > 15) { + newLabel = newLabel - 16; + } + $._PPP_.updateEventPanel('Previous Label color = ' + currentLabel + '.'); + first.setColorLabel(newLabel); + $._PPP_.updateEventPanel('New Label color = ' + newLabel + '.'); + } else { + $._PPP_.updateEventPanel('Couldn\'t locate first projectItem.'); + } + }, + + getPPPInsertionBin: function() { + var nameToFind = 'Here\'s where PProPanel puts things.'; + var targetBin = $._PPP_.searchForBinWithName(nameToFind); + + if (targetBin === undefined) { + // If panel can't find the target bin, it creates it. + app.project.rootItem.createBin(nameToFind); + targetBin = $._PPP_.searchForBinWithName(nameToFind); + } + if (targetBin) { + targetBin.select(); + return targetBin; + } else { + $._PPP_.updateEventPanel('Couldn\'t find or create a target bin.'); + } + }, + + importComps: function() { + var targetBin = $._PPP_.getPPPInsertionBin(); + if (targetBin) { + var filterString = ''; + if (Folder.fs === 'Windows') { + filterString = 'All files:*.*'; + } + var compNamesToImport = []; + var aepToImport = File.openDialog( + 'Choose After Effects project', // title + filterString, // filter available files? + false + ); // allow multiple? + if (aepToImport) { + var importAll = confirm( + 'Import all compositions in project?', + false, + 'Import all?' + ); + if (importAll) { + var result = app.project.importAllAEComps( + aepToImport.fsName, + 0, + targetBin + ); + } else { + var compName = prompt( + 'Name of composition to import?', + '', + 'Which Comp to import' + ); + if (compName) { + compNamesToImport[0] = compName; + var importAECompResult = app.project.importAEComps( + aepToImport.fsName, + compNamesToImport, + targetBin + ); + } else { + $._PPP_.updateEventPanel('No composition specified.'); + } + } + } else { + $._PPP_.updateEventPanel('Could not open project.'); + } + } else { + $._PPP_.updateEventPanel('Could not find or create target bin.'); + } + }, + + consolidateProject: function() { + var pmo = app.projectManager.options; + + if (app.project.sequences.numSequences) { + if (pmo) { + var filterString = ''; + if (Folder.fs === 'Windows') { + filterString = 'Output Presets:*.epr'; + } + var outFolder = Folder.selectDialog('Choose output directory.'); + if (outFolder) { + var presetPath = ''; + var useSpecificPreset = confirm( + 'Would you like to select an output preset?', + false, + 'Are you sure...?' + ); + if (useSpecificPreset) { + var useThisEPR = File.openDialog( + 'Choose output preset (.epr file)', // title + filterString, // filter available files? + false + ); // allow multiple? + + if (useThisEPR) { + pmo.clipTranscoderOption = pmo.CLIP_TRANSCODE_MATCH_PRESET; + pmo.encoderPresetFilePath = useThisEPR.fsName; + } else { + $._PPP_.updateEventPanel('Couldn\'t find specified .epr file.'); + } + } else { + pmo.clipTranscoderOption = pmo.CLIP_TRANSCODE_MATCH_SEQUENCE; + } + var processAllSequences = confirm( + 'Process all sequences? No = just the first sequence found.', + true, + 'Process all?' + ); + if (processAllSequences) { + pmo.includeAllSequences = true; + } else { + pmo.includeAllSequences = false; + pmo.affectedSequences = [app.project.sequences[0]]; + } + + pmo.clipTransferOption = pmo.CLIP_TRANSFER_TRANSCODE; + pmo.convertAECompsToClips = false; + pmo.convertSyntheticsToClips = false; + pmo.copyToPreventAlphaLoss = false; + pmo.destinationPath = outFolder.fsName; + pmo.excludeUnused = false; + pmo.handleFrameCount = 0; + pmo.includeConformedAudio = true; + pmo.includePreviews = true; + pmo.renameMedia = false; + + var result = app.projectManager.process(app.project); + var errorList = app.projectManager.errors; + + if (errorList.length) { + for (var k = 0; k < errorList.length; k++) { + $._PPP_.updateEventPanel(errorList[k][0]); + } + } else { + $._PPP_.updateEventPanel( + app.project.name + + ' successfully processed to ' + + outFolder.fsName + + '.' + ); + } + return result; + } + } else { + $._PPP_.updateEventPanel('Could not get Project Manager options.'); + } + } else { + $._PPP_.updateEventPanel('No sequences available.'); + } + }, + + importMoGRT: function() { + var activeSeq = app.project.activeSequence; + if (activeSeq) { + var filterString = ''; + if (Folder.fs === 'Windows') { + filterString = 'Motion Graphics Templates:*.mogrt'; + } + var mogrtToImport = File.openDialog( + 'Choose MoGRT', // title + filterString, // filter available files? + false + ); // allow multiple? + if (mogrtToImport) { + var targetTime = activeSeq.getPlayerPosition(); + var vidTrackOffset = 0; + var audTrackOffset = 0; + var newTrackItem = activeSeq.importMGT( + mogrtToImport.fsName, + targetTime.ticks, + vidTrackOffset, + audTrackOffset + ); + if (newTrackItem) { + var moComp = newTrackItem.getMGTComponent(); + if (moComp) { + var params = moComp.properties; + for (var z = 0; z < params.numItems; z++) { + var thisParam = params[0]; + } + var srcTextParam = params.getParamForDisplayName('Main Title'); + if (srcTextParam) { + var val = srcTextParam.getValue(); + srcTextParam.setValue('New value set by PProPanel!'); + } + } + } + } else { + $._PPP_.updateEventPanel( + 'Unable to import ' + mogrtToImport.fsName + '.' + ); + } + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + reportCurrentProjectSelection: function() { + var viewIDs = app.getProjectViewIDs(); + var viewSelection = app.getProjectViewSelection(viewIDs[0]); // sample code optimized for a single open project + $._PPP_.projectPanelSelectionChanged(viewSelection, viewIDs[0]); + }, + + randomizeProjectSelection: function() { + var viewIDs = app.getProjectViewIDs(); + var firstProject = app.getProjectFromViewID(viewIDs[0]); + var arrayOfRandomProjectItems = []; + + for (var b = 0; b < app.project.rootItem.children.numItems; b++) { + var currentProjectItem = app.project.rootItem.children[b]; + if (Math.random() > 0.5) { + arrayOfRandomProjectItems.push(currentProjectItem); + } + } + if (arrayOfRandomProjectItems.length > 0) { + app.setProjectViewSelection(arrayOfRandomProjectItems, viewIDs[0]); + } + }, + + setAllProjectItemsOnline: function(startingBin) { + for (var k = 0; k < startingBin.children.numItems; k++) { + var currentChild = startingBin.children[k]; + if (currentChild) { + if (currentChild.type === ProjectItemType.BIN) { + $._PPP_.setAllProjectItemsOnline(currentChild); // warning; recursion! + } else if (currentChild.isOffline()) { + currentChild.changeMediaPath(currentChild.getMediaPath(), true); + if (currentChild.isOffline()) { + $._PPP_.updateEventPanel( + 'Failed to bring "' + currentChild.name + '" online.' + ); + } else { + $._PPP_.updateEventPanel( + '"' + currentChild.name + '" is once again online.' + ); + } + } + } + } + }, + + setAllOnline: function() { + var startingBin = app.project.rootItem; + $._PPP_.setAllProjectItemsOnline(startingBin); + }, + + setOffline: function() { + var viewIDs = app.getProjectViewIDs(); + for (var a = 0; a < app.projects.numProjects; a++) { + var currentProject = app.getProjectFromViewID(viewIDs[a]); + if (currentProject) { + if (currentProject.documentID === app.project.documentID) { + // We're in the right project! + var selectedItems = app.getProjectViewSelection(viewIDs[a]); + if (selectedItems && selectedItems.length > 0) { + for (var b = 0; b < selectedItems.length; b++) { + var currentItem = selectedItems[b]; + if (currentItem) { + if ( + !currentItem.isSequence() && + currentItem.type !== ProjectItemType.BIN + ) { + // For every selected item which isn't a bin or sequence... + if (currentItem.isOffline()) { + $._PPP_.updateEventPanel( + '"' + currentItem.name + '" was already offline.' + ); + } else { + var result = currentItem.setOffline(); + $._PPP_.updateEventPanel( + '"' + currentItem.name + '" is now offline.' + ); + } + } + } + } + } + } + } + } + }, + + updateFrameRate: function() { + var item = app.project.rootItem.children[0]; + if (item) { + if ( + item.type == ProjectItemType.FILE || + item.type == ProjectItemType.CLIP + ) { + // If there is an item, and it's either a clip or file... + item.setOverrideFrameRate(23.976); + } else { + $._PPP_.updateEventPanel( + 'You cannot override the frame rate of bins or sequences.' + ); + } + } else { + $._PPP_.updateEventPanel('No project items found.'); + } + }, + + onItemAddedToProject: function(whichProject, addedProjectItem) { + var msg = addedProjectItem.name + ' was added to ' + whichProject + '.'; + $._PPP_.updateEventPanel(msg); + }, + + registerItemAddedFxn: function() { + app.onItemAddedToProjectSuccess = $._PPP_.onItemAddedToProject; + }, + + myOnProjectChanged: function(documentID) { + var msg = 'Project with ID ' + documentID + ' Changed.'; + $._PPP_.updateEventPanel(msg); + }, + + registerProjectChangedFxn: function() { + app.bind('onProjectChanged', $._PPP_.myOnProjectChanged); + }, + + confirmPProHostVersion: function() { + var version = parseFloat(app.version); + if (version < 14.0) { + $._PPP_.updateEventPanel( + 'Note: PProPanel relies on features added in 14.0, but is currently running in ' + + version + + '.' + ); + } + }, + + changeMarkerColors: function() { + if (app.project.rootItem.children.numItems > 0) { + var projectItem = app.project.rootItem.children[0]; // assumes first item is footage. + if (projectItem) { + if ( + projectItem.type == ProjectItemType.CLIP || + projectItem.type == ProjectItemType.FILE + ) { + var markers = projectItem.getMarkers(); + if (markers) { + var markerCount = markers.numMarkers; + if (markerCount) { + for ( + var thisMarker = markers.getFirstMarker(); + thisMarker !== undefined; + thisMarker = markers.getNextMarker(thisMarker) + ) { + var oldColor = thisMarker.getColorByIndex(); + var newColor = oldColor + 1; + if (newColor > 7) { + // clamp to valid values + newColor = 0; + } + thisMarker.setColorByIndex(newColor); + $._PPP_.updateEventPanel( + 'Changed color of marker named "' + thisMarker.name + '" from ' + oldColor + ' to ' + newColor + '.' + ); + } + } + } + } else { + $._PPP_.updateEventPanel('Can only add markers to footage items.'); + } + } else { + $._PPP_.updateEventPanel('Could not find first projectItem.'); + } + } else { + $._PPP_.updateEventPanel('Project is empty.'); + } + }, + + changeSeqTimeCodeDisplay: function() { + var seq = app.project.activeSequence; + if (seq) { + var currentSeqSettings = app.project.activeSequence.getSettings(); + if (currentSeqSettings) { + var oldVidSetting = currentSeqSettings.videoDisplayFormat; + var timeAsText = seq + .getPlayerPosition() + .getFormatted( + currentSeqSettings.videoFrameRate, + app.project.activeSequence.videoDisplayFormat + ); + + currentSeqSettings.videoDisplayFormat = oldVidSetting + 1; + if (currentSeqSettings.videoDisplayFormat > TIMEDISPLAY_48Timecode) { + // clamp to valid values + currentSeqSettings.videoDisplayFormat = TIMEDISPLAY_24Timecode; + } + app.project.activeSequence.setSettings(currentSeqSettings); + $._PPP_.updateEventPanel( + 'Changed timecode display format for "' + + app.project.activeSequence.name + + '".' + ); + } + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + myActiveSequenceChangedFxn: function() { + $._PPP_.updateEventPanel( + app.project.activeSequence.name + ' changed, in some way.' + ); + }, + + mySequenceActivatedFxn: function() { + $._PPP_.updateEventPanel( + 'Active sequence is now ' + app.project.activeSequence.name + '.' + ); + }, + + myActiveSequenceSelectionChangedFxn: function() { + var seq = app.project.activeSequence; + if (seq) { + var sel = seq.getSelection(); + if (sel && sel !== 'Connection to object lost') { + $._PPP_.updateEventPanel( + sel.length + + ' track items selected in ' + + app.project.activeSequence.name + + '.' + ); + for (var i = 0; i < sel.length; i++) { + if (sel[i].name !== 'anonymous') { + $._PPP_.updateEventPanel( + 'Selected item ' + (i + 1) + ' == ' + sel[i].name + '.' + ); + } + } + } else { + $._PPP_.updateEventPanel('No clips selected.'); + } + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + myActiveSequenceStructureChangedFxn: function() { + $._PPP_.updateEventPanel( + 'Something in ' + app.project.activeSequence.name + 'changed.' + ); + }, + + registerActiveSequenceStructureChangedFxn: function() { + var success = app.bind( + 'onActiveSequenceStructureChanged', + $._PPP_.myActiveSequenceStructureChangedFxn + ); + }, + + registerActiveSequenceChangedFxn: function() { + var success = app.bind( + 'onActiveSequenceChanged', + $._PPP_.myActiveSequenceChangedFxn + ); + }, + + registerSequenceSelectionChangedFxn: function() { + var success = app.bind( + 'onActiveSequenceSelectionChanged', + $._PPP_.myActiveSequenceSelectionChangedFxn + ); + }, + + registerSequenceActivatedFxn: function() { + var success = app.bind( + 'onSequenceActivated', + $._PPP_.mySequenceActivatedFxn + ); + }, + + enableNewWorldScripting: function() { + app.enableQE(); + + var previousNWValue = qe.getDebugDatabaseEntry( + 'ScriptLayerPPro.EnableNewWorld' + ); + var previousInternalDOMValue = qe.getDebugDatabaseEntry( + 'dvascripting.EnabledInternalDOM' + ); + if (previousNWValue === 'true' && previousInternalDOMValue === 'true') { + qe.setDebugDatabaseEntry('ScriptLayerPPro.EnableNewWorld', 'false'); + qe.setDebugDatabaseEntry('dvascripting.EnabledInternalDOM', 'false'); + $._PPP_.updateEventPanel( + 'ScriptLayerPPro.EnableNewWorld and dvascripting.EnabledInternalDOM are now OFF.' + ); + } else { + qe.setDebugDatabaseEntry('ScriptLayerPPro.EnableNewWorld', 'true'); + qe.setDebugDatabaseEntry('dvascripting.EnabledInternalDOM', 'true'); + $._PPP_.updateEventPanel( + 'ScriptLayerPPro.EnableNewWorld and dvascripting.EnabledInternalDOM are now ON.' + ); + } + }, + + forceLogfilesOn: function() { + app.enableQE(); + var previousLogFilesValue = qe.getDebugDatabaseEntry( + 'CreateLogFilesThatDoNotExist' + ); + + if (previousLogFilesValue === 'true') { + $._PPP_.updateEventPanel('Force create Log files was already ON.'); + } else { + qe.setDebugDatabaseEntry('CreateLogFilesThatDoNotExist', 'true'); + $._PPP_.updateEventPanel('Set Force create Log files to ON.'); + } + }, + + insertOrAppendToTopTracks: function() { + var seq = app.project.activeSequence; + if (seq) { + var first = app.project.rootItem.children[0]; + if (first) { + var time = seq.getPlayerPosition(); + var newClip = seq.insertClip( + first, + time, + seq.videoTracks.numTracks - 1, + seq.audioTracks.numTracks - 1 + ); + if (newClip) { + $._PPP_.updateEventPanel( + 'Inserted ' + newClip.name + ', into ' + seq.name + '.' + ); + } + } else { + $._PPP_.updateEventPanel('Couldn\'t locate first projectItem.'); + } + } else { + $._PPP_.updateEventPanel('no active sequence.'); + } + }, + + closeAllProjectsOtherThanActiveProject: function() { + var viewIDs = app.getProjectViewIDs(); + var closeTheseProjects = []; + for (var a = 0; a < viewIDs.length; a++) { + var thisProj = app.getProjectFromViewID(viewIDs[a]); + if (thisProj.documentID !== app.project.documentID) { + closeTheseProjects[a] = thisProj; + } + } + // Why do this afterward? Because if we close projects in that loop [above], we change the active project, and scare the user. :) + for (var b = 0; b < closeTheseProjects.length; b++) { + $._PPP_.updateEventPanel('Closed ' + closeTheseProjects[b].name); + closeTheseProjects[b].closeDocument(); + } + }, + + countAdjustmentLayersInBin: function( + parentItem, + arrayOfAdjustmentLayerNames, + foundSoFar + ) { + for (var j = 0; j < parentItem.children.numItems; j++) { + var currentChild = parentItem.children[j]; + if (currentChild) { + if (currentChild.type == ProjectItemType.BIN) { + $._PPP_.countAdjustmentLayersInBin( + currentChild, + arrayOfAdjustmentLayerNames, + foundSoFar + ); // warning; recursion! + } else { + if (currentChild.isAdjustmentLayer()) { + arrayOfAdjustmentLayerNames[foundSoFar] = currentChild.name; + foundSoFar++; + } + } + } + } + $._PPP_.updateEventPanel( + foundSoFar + ' adjustment layers found in ' + app.project.name + '.' + ); + }, + + findAllAdjustmentLayersInProject: function() { + var arrayOfAdjustmentLayerNames = []; + var foundSoFar = 0; + var startingBin = app.project.rootItem; + + $._PPP_.countAdjustmentLayersInBin( + startingBin, + arrayOfAdjustmentLayerNames, + foundSoFar + ); + + if (arrayOfAdjustmentLayerNames.length) { + var remainingArgs = arrayOfAdjustmentLayerNames.length; + var message = remainingArgs + ' adjustment layers found: '; + + for (var i = 0; i < arrayOfAdjustmentLayerNames.length; i++) { + message += arrayOfAdjustmentLayerNames[i]; + remainingArgs--; + if (remainingArgs > 1) { + message += ', '; + } + if (remainingArgs === 1) { + message += ', and '; + } + if (remainingArgs === 0) { + message += '.'; + } + } + $._PPP_.updateEventPanel(message); + } else { + $._PPP_.updateEventPanel( + 'No adjustment layers found in ' + app.project.name + '.' + ); + } + }, + + consolidateDuplicates: function() { + var result = app.project.consolidateDuplicates(); + $._PPP_.updateEventPanel( + 'Duplicates consolidated in ' + app.project.name + '.' + ); + }, + + closeAllSequences: function() { + var seqList = app.project.sequences; + if (seqList.numSequences) { + for (var a = 0; a < seqList.numSequences; a++) { + var currentSeq = seqList[a]; + if (currentSeq) { + currentSeq.close(); + } else { + $._PPP_.updateEventPanel( + 'No sequences from ' + app.project.name + ' were open.' + ); + } + } + } else { + $._PPP_.updateEventPanel( + 'No sequences found in ' + app.project.name + '.' + ); + } + }, + + dumpAllPresets: function() { + var desktopPath = new File('~/Desktop'); + var outputFileName = + desktopPath.fsName + $._PPP_.getSep() + 'available_presets.txt'; + var exporters = app.encoder.getExporters(); + var outFile = new File(outputFileName); + outFile.encoding = 'UTF8'; + + outFile.open('w', 'TEXT', '????'); + + for (var i = 0; i < exporters.length; i++) { + var exporter = exporters[i]; + if (exporter) { + outFile.writeln('-----------------------------------------------'); + outFile.writeln( + i + + ':' + + exporter.name + + ' : ' + + exporter.classID + + ' : ' + + exporter.fileType + ); + var presets = exporter.getPresets(); + if (presets) { + outFile.writeln(presets.length + ' presets found.'); + outFile.writeln('+++++++++'); + outFile.writeln('+++++++++'); + for (var j = 0; j < presets.length; j++) { + var preset = presets[j]; + if (preset) { + outFile.writeln( + 'matchName: ' + preset.matchName + '(' + preset.name + ')' + ); + outFile.writeln('+++++++++'); + } + } + } + } + } + $._PPP_.updateEventPanel( + 'List of available presets saved to desktop as "available_presets.txt".' + ); + desktopPath.close(); + outFile.close(); + }, + + reportSequenceVRSettings: function() { + var seq = app.project.activeSequence; + if (seq) { + var settings = seq.getSettings(); + if (settings) { + $._PPP_.updateEventPanel( + '====================================================' + ); + $._PPP_.updateEventPanel('VR Settings for "' + seq.name + '":'); + $._PPP_.updateEventPanel(''); + $._PPP_.updateEventPanel(''); + $._PPP_.updateEventPanel( + ' Horizontal captured view: ' + settings.vrHorzCapturedView + ); + $._PPP_.updateEventPanel( + ' Vertical captured view: ' + settings.vrVertCapturedView + ); + $._PPP_.updateEventPanel(' Layout: ' + settings.vrLayout); + $._PPP_.updateEventPanel(' Projection: ' + settings.vrProjection); + $._PPP_.updateEventPanel(''); + $._PPP_.updateEventPanel(''); + $._PPP_.updateEventPanel( + '====================================================' + ); + } + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + openProjectItemInSource: function() { + var viewIDs = app.getProjectViewIDs(); + if (viewIDs) { + for (var a = 0; a < app.projects.numProjects; a++) { + var currentProject = app.getProjectFromViewID(viewIDs[a]); + if (currentProject) { + if (currentProject.documentID === app.project.documentID) { + // We're in the right project! + var selectedItems = app.getProjectViewSelection(viewIDs[a]); + if (selectedItems) { + for (var b = 0; b < selectedItems.length; b++) { + var currentItem = selectedItems[b]; + if (currentItem) { + if (currentItem.type !== ProjectItemType.BIN) { + // For every selected item which isn't a bin or sequence... + app.sourceMonitor.openProjectItem(currentItem); + } + } else { + $._PPP_.updateEventPanel('No item available.'); + } + } + } + } + } else { + $._PPP_.updateEventPanel('No project available.'); + } + } + } else { + $._PPP_.updateEventPanel('No view IDs available.'); + } + }, + + reinterpretFootage: function() { + var viewIDs = app.getProjectViewIDs(); + if (viewIDs) { + for (var a = 0; a < app.projects.numProjects; a++) { + var currentProject = app.getProjectFromViewID(viewIDs[a]); + if (currentProject) { + if (currentProject.documentID === app.project.documentID) { + // We're in the right project! + var selectedItems = app.getProjectViewSelection(viewIDs[a]); + if (selectedItems.length) { + for (var b = 0; b < selectedItems.length; b++) { + var currentItem = selectedItems[b]; + if (currentItem) { + if ( + currentItem.type !== ProjectItemType.BIN && + currentItem.isSequence() === false + ) { + var interp = currentItem.getFootageInterpretation(); + if (interp) { + interp.frameRate = 17.868; + interp.pixelAspectRatio = 1.2121; + currentItem.setFootageInterpretation(interp); + $._PPP_.updateEventPanel( + 'Changed frame rate and PAR for ' + + currentItem.name + + '.' + ); + } else { + $._PPP_.updateEventPanel( + 'Unable to get interpretation for ' + + currentItem.name + + '.' + ); + } + var mapping = currentItem.getAudioChannelMapping; + if (mapping) { + mapping.audioChannelsType = AUDIOCHANNELTYPE_Stereo; + mapping.audioClipsNumber = 1; + mapping.setMappingForChannel(0, 4); // 1st param = channel index, 2nd param = source index + mapping.setMappingForChannel(1, 5); + currentItem.setAudioChannelMapping(mapping); // submit changed mapping object + $._PPP_.updateEventPanel( + 'Modified audio channel type and channel mapping for ' + + currentItem.name + + '.' + ); + } + } + } else { + $._PPP_.updateEventPanel('No project item available.'); + } + } + } else { + $._PPP_.updateEventPanel('No items selected.'); + } + } + } else { + $._PPP_.updateEventPanel('No project available.'); + } + } + } else { + $._PPP_.updateEventPanel('No view IDs available.'); + } + }, + + createSubSequence: function() { + /* Behavioral Note + + createSubSequence() uses track targeting to select clips when there is + no current clip selection, in the sequence. To create a subsequence with + clips on tracks that are currently NOT targeted, either select some clips + (on any track), or temporarily target all desired tracks. + + */ + + var activeSequence = app.project.activeSequence; + if (activeSequence) { + var targetTrackFound = false; + var cloneAnyway = true; + for ( + var a = 0; + a < activeSequence.videoTracks.numTracks && targetTrackFound === false; + a++ + ) { + if (activeSequence.videoTracks[a].isTargeted()) { + targetTrackFound = true; + } + } + // If no targeted track was found, just target the first (zero-th) track, for demo purposes + if (targetTrackFound === false) { + activeSequence.videoTracks[0].setTargeted(true, true); + } + if ( + activeSequence.getInPoint() === NOT_SET && + activeSequence.getOutPoint() === NOT_SET + ) { + cloneAnyway = confirm( + 'No in or out points set; clone entire sequence?', + false, + 'Clone the whole thing?' + ); + } + if (cloneAnyway) { + var ignoreMapping = confirm( + 'Ignore track mapping?', + false, + 'Ignore track mapping?' + ); + var newSeq = activeSequence.createSubsequence(ignoreMapping); + // rename newSeq here, as desired. + } + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + selectAllRetimedClips: function() { + var activeSeq = app.project.activeSequence; + var numRetimedClips = 0; + if (activeSeq) { + var trackGroups = [activeSeq.audioTracks, activeSeq.videoTracks]; + var trackGroupNames = ['audioTracks', 'videoTracks']; + var updateUI = true; + for (var groupIndex = 0; groupIndex < 2; groupIndex++) { + var group = trackGroups[groupIndex]; + for (var trackIndex = 0; trackIndex < group.numTracks; trackIndex++) { + var track = group[trackIndex]; + var clips = track.clips; + for (var clipIndex = 0; clipIndex < clips.numItems; clipIndex++) { + var clip = clips[clipIndex]; + if (clip.getSpeed() !== 1) { + clip.setSelected(true, updateUI); + numRetimedClips++; + } + } + } + } + $._PPP_.updateEventPanel(numRetimedClips + ' retimed clips found.'); + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + selectReversedClips: function() { + var sequence = app.project.activeSequence; + var numReversedClips = 0; + if (sequence) { + var trackGroups = [sequence.audioTracks, sequence.videoTracks]; + var trackGroupNames = ['audioTracks', 'videoTracks']; + var updateUI = true; + + for (var groupIndex = 0; groupIndex < 2; groupIndex++) { + var group = trackGroups[groupIndex]; + for (var trackIndex = 0; trackIndex < group.numTracks; trackIndex++) { + for ( + var clipIndex = 0; + clipIndex < group[trackIndex].clips.numItems; + clipIndex++ + ) { + var clip = group[trackIndex].clips[clipIndex]; + var isReversed = clip.isSpeedReversed(); + if (isReversed) { + clip.setSelected(isReversed, updateUI); + numReversedClips++; + } + } + } + } + $._PPP_.updateEventPanel(numReversedClips + ' reversed clips found.'); + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + logConsoleOutput: function() { + app.enableQE(); + var logFileName = 'PPro_Console_output.txt'; + var outFolder = Folder.selectDialog( + 'Where do you want to save the log file?' + ); + if (outFolder) { + var entireOutputPath = outFolder.fsName + $._PPP_.getSep() + logFileName; + var result = qe.executeConsoleCommand('con.openlog ' + entireOutputPath); + $._PPP_.updateEventPanel('Log opened at ' + entireOutputPath + '.'); + } else { + $._PPP_.updateEventPanel('No output folder selected.'); + } + }, + + closeLog: function() { + app.enableQE(); + qe.executeConsoleCommand('con.closelog'); + }, + + stitch: function(presetPath) { + var viewIDs = app.getProjectViewIDs(); + var allPathsToStitch = ''; + + for (var a = 0; a < app.projects.numProjects; a++) { + var currentProject = app.getProjectFromViewID(viewIDs[a]); + if (currentProject) { + if (currentProject.documentID === app.project.documentID) { + // We're in the right project! + var selectedItems = app.getProjectViewSelection(viewIDs[a]); + if (selectedItems.length > 1) { + for (var b = 0; b < selectedItems.length; b++) { + var currentItem = selectedItems[b]; + if (currentItem) { + if ( + !currentItem.isSequence() && + currentItem.type !== ProjectItemType.BIN + ) { + // For every selected item which isn't a bin or sequence... + allPathsToStitch += currentItem.getMediaPath(); + allPathsToStitch += ';'; + } + } + } + var AMEString = + 'var fe = app.getFrontend(); fe.stitchFiles("' + allPathsToStitch + '"'; + var addendum = ', \'H.264\', \'' + presetPath + '\', \'(This path parameter is never used)\');'; + + AMEString += addendum; + var bt = new BridgeTalk(); + bt.target = 'ame'; + bt.body = AMEString; + bt.send(); + } else { + $._PPP_.updateEventPanel( + 'Select more than one render-able item, then try stitching again.' + ); + } + } + } + } + }, + + myTrackItemAdded: function(track, trackItem) { + $._PPP_.updateEventPanel( + 'onActiveSequenceTrackItemAdded : ' + + track.name + + ' : ' + + trackItem.name + + ' : ' + + trackItem.nodeId + + '.' + ); + }, + + myTrackItemRemoved: function(track, trackItem) { + $._PPP_.updateEventPanel( + 'onActiveSequenceTrackItemRemoved : ' + + track.name + + ' : ' + + trackItem.name + + ' : ' + + trackItem.nodeId + + '.' + ); + }, + + mySequenceStructureChanged: function() { + $._PPP_.updateEventPanel('onActiveSequenceStructureChanged.'); + }, + + registerSequenceMessaging: function() { + app.bind('onActiveSequenceTrackItemRemoved', $._PPP_.myTrackItemRemoved); + app.bind('onActiveSequenceTrackItemAdded', $._PPP_.myTrackItemAdded); + app.bind( + 'onActiveSequenceStructureChanged', + $._PPP_.mySequenceStructureChanged + ); + }, + + enumerateTeamProjects: function() { + app.enableQE(); + var numTeamProjectsOpen = 0; + for (var i = 0; i < app.projects.numProjects; i++) { + var project = app.projects[i]; + if (project.isCloudProject) { + numTeamProjectsOpen++; + $._PPP_.updateEventPanel(project.name + ' is a cloud-based project.'); + var localHubID = project.cloudProjectLocalID; + $._PPP_.updateEventPanel('LocalHub Id is ' + localHubID + '.'); + var production = qe.ea.getProductionByID(localHubID); + $._PPP_.updateEventPanel('Production Name is ' + production.name + '.'); + var remoteID = production.getRemoteProductionID(); + $._PPP_.updateEventPanel('Remote Production Id is ' + remoteID + '.'); + } + } + if (numTeamProjectsOpen === 0) { + $._PPP_.updateEventPanel('No open Team Projects found.'); + } else { + $._PPP_.updateEventPanel( + numTeamProjectsOpen + ' open Team Projects Team Projects found.' + ); + } + }, + + enableWorkArea: function(enable) { + var seq = app.project.activeSequence; + if (seq) { + var newStateString = 'undefined'; + seq.setWorkAreaEnabled(enable); + var newState = seq.isWorkAreaEnabled(); + if (newState) { + newStateString = 'ON'; + } else { + newStateString = 'OFF'; + } + var update = + 'Work area for ' + + app.project.activeSequence.name + + ' is now ' + + newStateString + + '.'; + $._PPP_.updateEventPanel(update); + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + modifyWorkArea: function() { + var seq = app.project.activeSequence; + if (seq) { + var workAreaIsEnabled = seq.isWorkAreaEnabled(); + if (!workAreaIsEnabled) { + var confirmString = 'Enable work area for ' + seq.name + '?'; + var turnOn = confirm(confirmString, true, 'Are you sure...?'); + if (turnOn) { + $._PPP_.enableWorkArea(true); + } + } + var oldIn = seq.getWorkAreaInPointAsTime(); + var oldOut = seq.getWorkAreaOutPointAsTime(); + var newIn = oldIn; + var newOut = oldOut; + var duration = oldOut.seconds - oldIn.seconds; + newIn.seconds = oldIn.seconds + 10; + newOut.seconds = oldOut.seconds - 10; + + seq.setWorkAreaInPoint(newIn.seconds); + seq.setWorkAreaOutPoint(newOut.seconds); + } + }, + + setLocale: function(localeFromCEP) { + $.locale = localeFromCEP; + $._PPP_.updateEventPanel( + 'ExtendScript Locale set to ' + localeFromCEP + '.' + ); + }, + + disableTranscodeOnIngest: function(newValue) { + return app.setEnableTranscodeOnIngest(newValue); + }, + + generateSystemCompatibilityReport: function() { + app.enableQE(); + var outputPath = new File('~/Desktop'); + var outputFileName = + outputPath.fsName + $._PPP_.getSep() + 'System_Compatibility_Report.txt'; + SystemCompatibilityReport.CreateReport(outputFileName); + $._PPP_.updateEventPanel( + 'System Compatibility report and project analysis report saved to user\'s Desktop.' + ); + }, + + changeSequenceColorSpace: function() { + var seq = app.project.activeSequence; + if (seq) { + var currentSeqSettings = seq.getSettings(); + if (currentSeqSettings) { + if ( + currentSeqSettings.workingColorSpace === + currentSeqSettings.workingColorSpaceList[0] + ) { + currentSeqSettings.workingColorSpace = + currentSeqSettings.workingColorSpaceList[1]; + seq.setSettings(currentSeqSettings); + $._PPP_.updateEventPanel( + 'Changed sequence colorspace from \'' + + currentSeqSettings.workingColorSpaceList[0] + + '\' to \'' + + currentSeqSettings.workingColorSpaceList[1] + + '\'.' + ); + } else { + currentSeqSettings.workingColorSpace = + currentSeqSettings.workingColorSpaceList[0]; + seq.setSettings(currentSeqSettings); + $._PPP_.updateEventPanel( + 'Changed sequence colorspace to \'' + + currentSeqSettings.workingColorSpaceList[0] + + '\'.' + ); + } + // Now, let's make sure all video clips in the sequence match the sequence's new colorspace. + for ( + var trackIndex = 0; + trackIndex < seq.videoTracks.numTracks; + trackIndex++ + ) { + var track = seq.videoTracks[trackIndex]; + var clips = track.clips; + for (var clipIndex = 0; clipIndex < clips.numItems; clipIndex++) { + var clip = clips[clipIndex]; + if (clip.projectItem) { + var oldColorSpace = clip.projectItem.getColorSpace(); + clip.projectItem.setOverrideColorSpace( + currentSeqSettings.workingColorSpace + ); + $._PPP_.updateEventPanel( + 'Previous color space for ' + + clip.projectItem.name + + ' was: ' + + oldColorSpace + + '.' + ); + $._PPP_.updateEventPanel( + clip.name + + ' colorspace changed to \'' + + currentSeqSettings.workingColorSpace + + '\'.' + ); + } else { + $._PPP_.updateEventPanel( + 'No project item available, from ' + clip.name + '.' + ); + } + } + } + } else { + $._PPP_.updateEventPanel( + 'Could not obtain settings for ' + seq.name + '.' + ); + } + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + autoReframeActiveSequence: function() { + var seq = app.project.activeSequence; + if (seq) { + var numerator = 1; + var denominator = 1; + var motionPreset = '​Sensitive'; // valid values = '​Sensitive', '​LessSensitive', and '​MoreSensitive' + var newName = seq.name + ',auto-reframed by PProPanel.'; + var useNestedSeqs = false; + + var newSequence = seq.autoReframeSequence( + numerator, + denominator, + motionPreset, + newName, + useNestedSeqs + ); + + if (newSequence) { + $._PPP_.updateEventPanel('Created reframed sequence: ' + newName + '.'); + } else { + $._PPP_.updateEventPanel( + 'Failed to create re-framed sequence: ' + newName + '.' + ); + } + } + } +}; diff --git a/pype/premiere/extensions/com.pype/jsx/PlugPlugExternalObject.d.ts b/pype/premiere/extensions/com.pype/jsx/PlugPlugExternalObject.d.ts new file mode 100644 index 00000000000..8138887d895 --- /dev/null +++ b/pype/premiere/extensions/com.pype/jsx/PlugPlugExternalObject.d.ts @@ -0,0 +1,91 @@ +/// + +interface ExternalObjectConstructor { + readonly prototype: ExternalObject + + /** + * Creates a new ExternalObject object. + */ + new (lib: string): ExternalObject + (lib: string): ExternalObject +} +declare const ExternalObject: ExternalObjectConstructor + +interface ExternalObject { + /** + * Set to true to write status information to standard output (the + * JavaScript Console in the ExtendScript Toolkit). Set to false to turn + * logging off. Default is false. + */ + log: boolean + + /** + * A set of alternate paths in which to search for the shared library files, a + * single string with multiple path specifications delimited by semicolons + * (;). Paths can be absolute or relative to the Folder.startup location. + */ + searchFolders: string + + /** + * The version of the library, as returned by ESGetVersion() + */ + version: number + + /** + * Reports whether a compiled C/C++ library can be found, but does not load it. If logging is on, the + * paths searched are reported to the JavaScript Console in the ExtendScript Toolkit. + * Returns true if the library is found, false otherwise. + * @param spec The file specification for the compiled library, with or without path information. + */ + search(spec: string): boolean + + /** + * Explicitly shuts down the ExternalObject dynamic library wrapped by this instance. + * It can be helpful to force a shutdown of the external library if termination of external libraries during + * the shutdown of the hosting application does not occur in the correct order. + */ + terminate(): undefined +} + +interface CSXSEventConstructor { + readonly prototype: CSXSEvent + + /** + * Creates a new CSXSEvent object. + */ + new (type?: string, scope?: string, data?: string): CSXSEvent + (type?: string, scope?: string, data?: string): CSXSEvent +} +declare const CSXSEvent: CSXSEventConstructor + +interface CSXSEvent { + /** + * Retrieves the unique identifier of the application from which this event was dispatched. + */ + readonly appId: string + + /** + * Retrieves or sets the payload of this event. + */ + data: string + + /** + * Retrieves the unique identifier of the extension from which this event was dispatched. + */ + readonly extensionId: string + + /** + * Retrieves the scope of this event. + */ + scope: string + + /** + * Retrieves the type of this event. + */ + type: string + + /** + * Dispatch the event + */ + dispatch(): void +} diff --git a/pype/premiere/extensions/com.pype/jsx/PremierePro.14.0.d.ts b/pype/premiere/extensions/com.pype/jsx/PremierePro.14.0.d.ts new file mode 100644 index 00000000000..fe4566b3a7e --- /dev/null +++ b/pype/premiere/extensions/com.pype/jsx/PremierePro.14.0.d.ts @@ -0,0 +1,2239 @@ +/** + * TypeScript definitions for Premiere Pro's ExtendScript API would not have happened + * without the efforts of Eric Robinson and Pravdomil Toman. If you find these definitions + * useful, it's thanks to them. If you find problems with them, they're mine. + * + * -bbb + * 4/15/19 + * + */ + +/** + * 0 = false, + * 1 = true + */ + +type NumericalBool = 0 | 1; +type MediaType = "Video" | "Audio" | "any"; +type SampleRateOption = 48000 | 96000; +type BitsPerSampleOption = 16 | 24; +type SDKEventType = "warning" | "info" | "error"; + +interface $ +{ + _PPP_: any; +} +/** + * + */ +declare class ProjectItemType { +/** + * + */ +static readonly BIN: number + +/** + * + */ +static readonly CLIP: number + +/** + * + */ +static readonly FILE: number + +/** + * + */ +static readonly ROOT: number + +/** + * + */ +bind(eventName: string, function_: any): void + +/** + * + */ +setTimeout(eventName: string, function_: any, milliseconds: number): void + +/** + * + */ +unbind(eventName: string): void +} + +/** + * Structure containing sequence settings. + */ +declare class SequenceSettings { + audioChannelCount: number + audioChannelType: number + audioDisplayFormat: number + audioSampleRate: Time + compositeLinearColor: boolean + editingMode: String + maximumBitDepth: boolean + maximumRenderQuality: boolean + previewCode: String + previewFileFormat: String + previewFrameHeight: number + previewFrameWidth: number + videoDisplayFormat: number + videoFieldType: number + videoFrameRate: Time + videoFrameHeight: number + videoFrameWidth: number + videoPixelAspectRatio: number + vrHorzCapturedView: number + vrLayout: number + vrProjection: number + vrVertCapturedView: number + workingColorSpaceList: Array + workingColorSpace: String +} + +/** + * A sequence. + */ +declare class Sequence { + + /** + * + */ + sequenceSettings: SequenceSettings + + /** + * A collection of the sequence's audio tracks. + */ + readonly audioTracks: TrackCollection + + /** + * Timecode (as a string) of the end of the sequence. + */ + readonly end: string + + /** + * Width + */ + readonly frameSizeHorizontal: number + + /** + * Height + */ + readonly frameSizeVertical: number + + /** + * Sequence ID + */ + readonly id: number + + /** + * The sequence's markers. + */ + readonly markers: MarkerCollection + + /** + * The available colorspaces + */ + readonly workingColorSpaceList: Array + + /** + * The color space in use by the sequence + */ + workingColorSpace: string + + /** + * Name (writable). + */ + name: string + + /** + * + */ + videoDisplayFormat: number + + /** + * The `projectItem` corresponding to the sequence. + */ + readonly projectItem: ProjectItem + + /** + * Permanent ID of the sequence, within its project. + */ + readonly sequenceID: string + + /** + * + */ + readonly timebase: string + + /** + * + */ + readonly videoTracks: TrackCollection + + /** + * The starting timecode of the first frame of the sequence, as a string. + */ + readonly zeroPoint: string + + /** + * Adds a new metadata key to the sequence, and sets its value. + * @param propertyID Name of new property + * @param propertyValue Value of new property + */ + attachCustomProperty(propertyID: string, propertyValue: string): void + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * Clones a sequence. + * @returns the clone Sequence. + */ + clone(): Sequence + + /** + * Creates a new sequence from the source sequence's in and out points. + * @param ignoreMapping If True the current selection, not track targeting, will determine + * the clips to include in the new sequence. + * + * If there is no selection, track targeting determines which clips are included in the new sequence. + */ + createSubsequence(ignoreMapping:Boolean): Sequence + + /** + * Exports a new FCP XML file representing this sequence. + * @param exportPath The full file path (with file name) to create. + * @param suppressUI Optional; quiets any warnings or errors encountered during export. + */ + exportAsFinalCutProXML(exportPath: string, suppressUI?: number): boolean + + /** + * Premiere Pro exports the sequence immediately. + * @param outputFilePath The output file path (with name). + * @param presetPath The .epr file to use. + * @param workAreaType Optional work area specifier. + */ + exportAsMediaDirect(outputFilePath: string, presetPath: string, workAreaType?: number): string + + /** + * Exports the sequence (and its constituent media) as a new PPro project. + * @param path Output file path, including file name. + */ + exportAsProject(exportPath: string): void + + /** + * Retrieves the file extension associated with a given output preset (.epr file). + * @param presetFilePath full path to .epr file + */ + getExportFileExtension(presetFilePath: string): string + + /** + * Retrieves the sequence's in point, as a timecode string. + */ + getInPoint(): string + + /** + * Retrieves the sequence's out point, as a timecode string. + */ + getOutPoint(): string + + /** + * Retrieves the sequence's in point, as a `Time` object. + */ + getInPointAsTime(): Time + + /** + * Retrieves the sequence's out point, as a `Time` object. + */ + getOutPointAsTime(): Time + + + /** + * Retrieves the current player position, as a `Time` object. + */ + getPlayerPosition(): Time + + /** + * Sets the in point of the sequence. + * @param seconds Time of in point. + */ + setInPoint(seconds: number): void + + /** + * Sets the out point of the sequence. + * @param seconds Time of out point. + */ + setOutPoint(seconds: number): void + + /** + * Sets the current player position. + * @param pos The new position, as a timecode string. + */ + setPlayerPosition(pos: string): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * Sets the timecode of the first frame of the sequence. + * @param newStartTime The new starting time, in `ticks`. + */ + setZeroPoint(newStartTime: string): void + + /** + * Links the currently-selected `trackItems` together, if possible. + * @returns `True` if successful. + */ + linkSelection(): boolean + + /** + * Unlinks the currently-selected `trackItems`, if possible. + * @returns `True` if successful. + */ + unlinkSelection(): boolean + + /** + * Imports a Motion Graphics Template (.mogrt) into the sequence + * @param pathToMOGRT Complete path to .mogrt + * @param timeInTicks Time (in ticks) at which to insert + * @param videoTrackOffset The offset from first video track to targeted track + * @param audioTrackOffset The offset from first audio track to targeted track + * @returns newly-created `trackItem` representing the .mogrt + */ + importMGT(pathToMOGRT:String, timeInTicks:String, videoTrackOffset:number, audioTrackOffset:number): TrackItem + + /** + * Returns `true` if work area is enabled. + */ + isWorkAreaEnabled(): Boolean + + /** + * Sets the enabled state of the seqeuence work area. + * @param enableState The desired state + */ + setWorkAreaEnabled(enableState:Boolean): void + + /** + * Returns the work area in point, in seconds. + */ + getWorkAreaInPoint(): number + + /** + * Specify the work area in point, in seconds. + * @param timeInSeconds new in point time. + */ + setWorkAreaInPoint(timeInSeconds:number): void + + /** + * Returns the work area out point, in seconds. + */ + getWorkAreaOutPoint(): number + + /** + * Specify the work area out point, in seconds. + * @param timeInSeconds new out point time. + */ + setWorkAreaOutPoint(timeInSeconds:number): void + + /** + * @returns the work area in point, as a `Time` object. + */ + getWorkAreaInPointAsTime(): Time + + /** + * Specify the work area in point, as `Time`. + */ + setWorkAreaInPointAsTime(outPoint:Time): void + + /** + * @returns the work area out point, as a `Time` object. + */ + getWorkAreaOutPointAsTime(): Time + + /** + * Specify the work area out point, as `Time`. + */ + setWorkAreaOutPointAsTime(outPoint:Time): void + + /** + * Inserts a clip (`trackItem`) into the sequence. + * @param projectItem The project item to insert. + * @param time Time at which to insert. + * @param vidTrackOffset The offset from the first video track to targeted track + * @param audTrackOffset The offset from the first audio track to targeted track + */ + insertClip(projectItem:ProjectItem, time:Time, vidTrackOffset:number, audTrackOffset:number): TrackItem + + /** + * @returns currently-selected clips, as an `Array` of `trackItems` + */ + getSelection(): Array + + /** + * Returns the current sequence settings. + * @returns SequenceSettings + */ + getSettings(): SequenceSettings + + /** + * Specifies the sequence settings to use. + * @param newSettings New settings + */ + setSettings(newSettings): void + + + /** + * + * @param numerator Numerator of desired frame aspect ratio + * @param denominator Denominator of desired frame aspect ratio + * @param motionPreset Either "default", "faster" or "slower" + * @param sequenceName Name for created sequence + * @param nest Use nested sequences? + */ + + + autoReframeSequence(numerator:Number, denominator:Number, motionPreset:String, sequenceName:String, nest:Boolean): Sequence + + /** + * + */ + unbind(eventName: string): void + } + + +/** + * Structure containing all available options for the `ProjectManager`. + */ +declare class ProjectManagerOptions { + + /** + * Transfer mode setting: Copy source media + */ + readonly CLIP_TRANSFER_COPY: string + + /** + * Transfer mode setting: Transcode source media + */ + readonly CLIP_TRANSFER_TRANSCODE: string + + /** + * Transcode mode setting: Transcode source media to a specific preset + */ + readonly CLIP_TRANSCODE_MATCH_PRESET: string + + /** + * Transcode mode setting: Transcode source media to match clips + */ + readonly CLIP_TRANSCODE_MATCH_CLIPS: string + + /** + * Transcode mode setting: Transcode source media to match sequence settings + */ + readonly CLIP_TRANSCODE_MATCH_SEQUENCE: string + + /** + * Which transcode option to use; will be one of these: + * `CLIP_TRANSCODE_MATCH_PRESET` + * `CLIP_TRANSCODE_MATCH_CLIPS` + * `CLIP_TRANSCODE_MATCH_SEQUENCE` + */ + clipTranscoderOption: string + + /** + * Which transfer option to use; will be one of these: + * `CLIP_TRANSFER_COPY` + * `CLIP_TRANSFER_TRANSCODE` + */ + clipTransferOption + + /** + * If `true`, projectItems not used in a sequence are not transferred + */ + excludeUnused : boolean + + /** + * The number of 'handle' frames to provide, before and after the in/out points of clips in the sequence. + */ + handleFrameCount : number + + /** + * If `true`, preview files will also be transferred. + */ + includePreviews : boolean + + /** + * If `true`, conformed audio files will also be transferred. + */ + includeConformedAudio : boolean + + /** + * If `true`, media files will be renamed to match clip names. + */ + renameMedia : boolean + + /** + * The containing directory for the consolidation/transfer. + */ + destinationPath : String + + /** + * If `true`, all sequences in the project will be transferred. + */ + includeAllSequences : boolean + + /** + * An `Array` of all sequences affected by the transfer. + */ + affectedSequences : Array + + /** + * Path the the encoder preset (.epr file) to be used. + */ + encoderPresetFilePath : String + + /** + * If `true`, image sequences will be transcoded. + */ + convertImageSequencesToClips : boolean + + /** + * If `true`, synthetic importer clips will be transcoded. + */ + convertSyntheticsToClips : boolean + + /** + * If `true`, After Effects compositions will be transcoded. + */ + convertAECompsToClips : boolean + + /** + * If `true`, source media will be copied not transcoded, if transcoding would have resulted in loss of alpha information. + */ + copyToPreventAlphaLoss : boolean +} + +declare class ProjectManager { + + /** + * An array of strings describing errors encountered. + */ + errors : Array + + /** + * The `ProjectManagerOptions` structure. + */ + options : ProjectManagerOptions + + /** + * Perform the consolidation and transfer. + * @param project the `Project` to consolidate. + */ + process(project:Project): number + + /** + * + */ + unbind(eventName: string): void +} + + /** + * + */ + declare class SequenceCollection { + /** + * + */ + readonly numSequences: number + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class Metadata { + /** + * + */ + readonly getMetadata: string + + /** + * + */ + addMarker(): void + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + deleteMarker(): void + + /** + * + */ + setMarkerData(): void + + /** + * + */ + setMetadataValue(): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + + /** + * + */ + updateMarker(): void + } + + /** + * + */ + declare class Anywhere { + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + getAuthenticationToken(): string + + /** + * + */ + getCurrentEditingSessionActiveSequenceURL(): string + + /** + * + */ + getCurrentEditingSessionSelectionURL(): string + + /** + * + */ + getCurrentEditingSessionURL(): string + + /** + * + */ + isProductionOpen(): boolean + + /** + * + */ + listProductions(): RemoteProductionCollection + + /** + * + */ + openProduction(inProductionURL: string): boolean + + /** + * + */ + setAuthenticationToken(inAuthToken: string, inEmail: string): boolean + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class CsxsResourceCentral { + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + getBrightness(): string + + /** + * + */ + openURL(urlString: string): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + + /** + * + */ + validateClient(token: string): boolean + } + + /** + * + */ + declare class SourceMonitor { + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + closeAllClips(): void + + /** + * + */ + closeClip(): void + + /** + * + */ + openFilePath(filePath: string): boolean + + /** + * + */ + play(speed?: number): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + + /** + * + */ + getPosition(): Time + + /** + * + */ + openProjectItem(itemToOpen:ProjectItem): void + + } + + /** + * + */ + declare class Time { + /** + * + */ + seconds: number + + /** + * + */ + ticks: string + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + getFormatted(Time, whichFormat:number): String + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class ProjectItemType { + /** + * + */ + static readonly BIN: number + + /** + * + */ + static readonly CLIP: number + + /** + * + */ + static readonly FILE: number + + /** + * + */ + static readonly ROOT: number + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class Project { + /** + *f + */ + activeSequence: Sequence + + /** + * + */ + readonly documentID: string + + /** + * + */ + readonly name: string + + /** + * + */ + readonly path: string + + /** + * + */ + readonly rootItem: ProjectItem + + /** + * + */ + readonly sequences: SequenceCollection + + /** + * + */ + addPropertyToProjectMetadataSchema(name: string, label: string, type: number): boolean + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + closeDocument(): boolean + + /** + * + */ + createNewSequence(sequenceName: string, placeholderID: string): void + + /** + * + */ + deleteAsset(): void + + /** + * + */ + deleteSequence(sequence: Sequence): boolean + + /** + * + */ + exportAAF( + sequence: Sequence, + filePath: string, + mixDownVideo: number, + explodeToMono: number, + sampleRate: number, + bitsPerSample: number, + embedAudio: number, + audioFileFormat: number, + trimSources: number, + handleFrames: number, + ): number + + /** + * + */ + exportFinalCutProXML(exportPath: string, suppressUI: number): boolean + + /** + * + */ + consolidateDuplicates(): void + + /** + * + */ + exportOMF( + sequence: Sequence, + filePath: string, + OMFTitle: string, + sampleRate: number, + bitsPerSample: number, + audioEncapsulated: number, + audioFileFormat: number, + trimAudioFiles: number, + handleFrames: number, + includePan: number, + ): number + + /** + * + */ + exportTimeline(exportControllerName: string): number + + /** + * + */ + getInsertionBin(): ProjectItem + + /** + * + */ + getProjectPanelMetadata(): string + + /** + * + */ + importAEComps(aepPath: String, compsToImport: Array, projectBin: ProjectItem): boolean + + /** + * + */ + importAllAEComps(arg1: any, compsToImport: Array, projectBin: ProjectItem): boolean + + /** + * Imports files into the project. + * @param arrayOfFilePathsToImport An array of paths to files to import + * @param suppressUI optional; if true, suppress any warnings, translation reports, or errors. + * @param projectBin optional; if present, the bin into which to import the new media. + * @param importAsNumberedStill optiona; if present, interprets the file paths as a series of numbered stills. + */ + importFiles(arrayOfFilePathsToImport: string[], suppressUI?: boolean, projectBin?: ProjectItem, importAsNumberedStill?: boolean): boolean + + /** + * Imports sequences from a project. + * @param projectPath Path to project from which to import sequences. + * @param sequences An array of sequence IDs to import, from the project. + */ + importSequences(projectPath: String, sequencesToImport: Array): boolean + + /** + * + */ + openSequence(sequenceID: string): boolean + + /** + * + */ + pauseGrowing(pausedOrNot: number): boolean + + /** + * + */ + placeAsset(arg1: any): boolean + + /** + * + */ + save(): void + + /** + * + */ + saveAs(saveAsPath: string): boolean + + /** + * + */ + setProjectPanelMetadata(newMetadata: string): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class Track { + /** + * + */ + name: String + + /** + * + */ + readonly clips: TrackItemCollection + + /** + * + */ + readonly id: number + + /** + * + */ + readonly mediaType: string + + /** + * + */ + readonly transitions: TrackItemCollection + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + insertClip(clipProjectItem: ProjectItem, time: number): void + + /** + * + */ + isMuted(): boolean + + /** + * + */ + overwriteClip(clipProjectItem: ProjectItem, time: number): void + + /** + * + */ + setMute(arg1?: number): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + isTargeted(): Boolean + + /** + * + */ + setTargeted(isTargeted:Boolean, shouldBroadcast:Boolean): Boolean + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class TrackItem { + /** + * + */ + readonly components: any + + /** + * + */ + readonly duration: Time + + /** + * + */ + readonly end: Time + + /** + * + */ + readonly inPoint: Time + + /** + * + */ + readonly mediaType: string + + /** + * + */ + name: string + + /** + * + */ + readonly outPoint: Time + + /** + * + */ + projectItem: ProjectItem + + /** + * + */ + readonly start: Time + + /** + * + */ + readonly type: number + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + getLinkedItems(): TrackItemCollection + + /** + * + */ + isSelected(): boolean + + /** + * + */ + isSpeedReversed(): boolean + + /** + * + */ + setSelected(isSelected: boolean, updateUI?: boolean): void + + /** + * + */ + isAdjustmentLayer(): boolean + + /** + * + */ + remove(rippleEdit:boolean, alignToVideo:boolean): boolean + + /** + * + */ + getSpeed(): number + + /** + * + */ + getMGTComponent(): any + + /** + * + */ + getColorSpace(): String + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class ProjectItem { + /** + * + */ + readonly children: ProjectItemCollection + + /** + * + */ + name: string + + /** + * + */ + readonly nodeId: string + + /** + * + */ + readonly treePath: string + + /** + * + */ + readonly type: number + + /** + * + */ + readonly videoComponents: any + + /** + * + */ + attachProxy(mediaPath: string, isHiRes: number): boolean + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + canChangeMediaPath(): boolean + + /** + * + */ + canProxy(): boolean + + /** + * + */ + changeMediaPath(mediaPath: string, suppressWarnings: boolean): boolean + + /** + * + */ + createBin(name: string): ProjectItem + + /** + * + */ + createSmartBin(name: string, query: string): void + + /** + * Returns whether the projectItem represents a sequence. + @returns true, if projectItem is a sequence. + */ + isSequence(): boolean + + /** + * + */ + createSubClip( + name: string, + startTime: object, + endTime: object, + hasHardBoundaries: number, + takeVideo?: number, + takeAudio?: number, + ): ProjectItem + + /** + * + */ + deleteBin(): void + + /** + * + */ + findItemsMatchingMediaPath(matchString: string, ignoreSubclips?: number): void + + /** + * + */ + getColorLabel(): number + + /** + * + */ + getMarkers(): MarkerCollection + + /** + * + */ + getMediaPath(): string + + /** + * + */ + getProjectMetadata(): string + + /** + * + */ + getProxyPath(): string + + /** + * + */ + getXMPMetadata(): string + + /** + * + */ + hasProxy(): boolean + + /** + * + */ + moveBin(destination: ProjectItem): void + + /** + * + */ + refreshMedia(): string + + /** + * + */ + renameBin(name: string): boolean + + /** + * + */ + select(): void + + /** + * + */ + setColorLabel(newColor: number): void + + /** + * + */ + setOverridePixelAspectRatio(numerator: number, denominator: number): boolean + + /** + * + */ + setOverrideFrameRate(newFrameRate: number): boolean + + /** + * + */ + setProjectMetadata(buffer: String, keysToBeUpdated: Array): void + + /** + * + */ + setScaleToFrameSize(): void + + /** + * + */ + setStartTime(arg1: object): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + setXMPMetadata(buffer: String): boolean + + /** + * + */ + startTime(): Time + + /** + * + * @param newColorSpace value must be available via sequence.workingColorSpaceList + */ + setOverrideColorSpace(newColorSpace: String): void + + /** + * + */ + getColorSpace(): String + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class ProjectCollection { + /** + * + */ + readonly numProjects: number + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class ProjectItemCollection { + /** + * + */ + readonly numItems: number + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + + /** + * + */ + [index: number]: ProjectItem + } + + /** + * + */ + declare class TrackCollection { + /** + * + */ + readonly numTracks: number + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + + /** + * + */ + [index: number]: Track + } + + /** + * + */ + declare class TrackItemCollection { + + /**Number of items + * + */ + readonly numItems: number + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + + /** + * + */ + [index: number]: TrackItem + } + + /** + * + */ + declare class ScratchDiskType { + /** + * + */ + static readonly FirstAudioCaptureFolder: string + + /** + * + */ + static readonly FirstAudioPreviewFolder: string + + /** + * + */ + static readonly FirstAutoSaveFolder: string + + /** + * + */ + static readonly FirstCClibrariesFolder: string + + /** + * + */ + static readonly FirstCapsuleMediaFolder: string + + /** + * + */ + static readonly FirstVideoCaptureFolder: string + + /** + * + */ + static readonly FirstVideoPreviewFolder: string + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class Csxs { + /** + * + */ + readonly resourceCentral: CsxsResourceCentral + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class RemoteProductionCollection { + /** + * + */ + readonly numProductions: number + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class RemoteProduction { + /** + * + */ + readonly description: string + + /** + * + */ + readonly name: string + + /** + * + */ + readonly url: string + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class Encoder { + /** + * + */ + readonly ENCODE_ENTIRE: number + + /** + * + */ + readonly ENCODE_IN_TO_OUT: number + + /** + * + */ + readonly ENCODE_WORKAREA: number + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + encodeFile( + inputFilePath: string, + outputFilePath: string, + presetPath: string, + removeOnCompletion?: number, + startTime?: object, + stopTime?: object, + ): string + + /** + * + */ + encodeProjectItem( + projectItem: ProjectItem, + outputFilePath: string, + presetPath: string, + WorkAreaType?: number, + removeOnCompletion?: number, + ): string + + /** + * + */ + encodeSequence( + sequence: Sequence, + outputFilePath: string, + presetPath: string, + WorkAreaType?: number, + removeOnCompletion?: number, + ): string + + /** + * + */ + getExporters(): Array + /** + * + */ + launchEncoder(): boolean + + /** + * + */ + setEmbeddedXMPEnabled(enable: number): void + + /** + * + */ + setSidecarXMPEnabled(enable: number): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + startBatch(): boolean + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class Properties { + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + clearProperty(propertyKey: string): void + + /** + * + */ + doesPropertyExist(propertyKey: string): boolean + + /** + * + */ + getProperty(propertyKey: string): void + + /** + * + */ + isPropertyReadOnly(propertyKey: string): boolean + + /** + * + */ + setProperty(propertyKey: string, propertyValue: string, permanenceValue: number, allowCreateNewProperty: boolean): void + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class Application { + /** + * + */ + readonly anywhere: Anywhere + + /** + * + */ + readonly build: string + + /** + * + */ + readonly csxs: Csxs + + /** + * + */ + readonly encoder: Encoder + + /** + * + */ + readonly projectManager: ProjectManager + + + /** + * + */ + readonly getAppPrefPath: string + + /** + * + */ + readonly getAppSystemPrefPath: string + + /** + * + */ + readonly getPProPrefPath: string + + /** + * + */ + readonly getPProSystemPrefPath: string + + /** + * + */ + readonly metadata: Metadata + + /** + * This is the current active project. + */ + project: Project + + /** + * + */ + readonly projects: ProjectCollection + + /** + * + */ + readonly properties: Properties + + /** + * + */ + readonly sourceMonitor: SourceMonitor + + /** + * + */ + readonly userGuid: string + + /** + * + */ + readonly version: string + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + broadcastPrefsChanged(preferencesThatChanged: string): boolean + + /** + * + */ + getEnableProxies(): number + + /** + * Checks whether file specified is a doc + * @param filePath This is the path to be checked + * @returns true if the document at that path is openable as a PPro project + */ + isDocument(filePath: string): boolean + + /** + * + */ + isDocumentOpen(): boolean + + /** + * + */ + openDocument(filePath: string, bypassConversionDialog: boolean, bypassLocateFile: boolean, hideFromMRUList: boolean): boolean + + /** + * @param newValueForTranscodeOnIngest + * @returns the newly-set state for whether or not PPro transcodes files upon ingest. + */ + setEnableTranscodeOnIngest(newValueForTranscodeOnIngest: boolean) + + /** + * + */ + openFCPXML(): boolean + + /** + * + */ + quit(): void + + /** + * + */ + setEnableProxies(enable: number): boolean + + /** + * + */ + setExtensionPersistent(extensionID: string, state?: number): void + + /** + * + */ + setSDKEventMessage(value: string, eventType: string): boolean + + /** + * + */ + setScratchDiskPath(value: string, type: string): boolean + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + getProjectViewIDs(): Array + + /** + * + */ + getProjectFromViewID(viewID:String): Project + + /** + * + */ + showCursor(enable: boolean): void + + /** + * + */ + getProjectViewSelection(viewID:String): Array + + /** + * + */ + setProjectViewSelection(projectItems:Array, viewID:String): void + + /** + * + */ + onItemAddedToProjectSuccess : undefined + + + /** + * @returns an array of the names of all available workspaces. + */ + getWorkspaces(): Array + + /** + * @param workspaceName Name of workspace to use + * @returns true if successful + */ + setWorkspace(workspaceName: string) + + /** + * + * @param eventName event to which to subscribe + * @param function_ function to be called + */ + addEventListener(eventName: string, function_: any): void + + /** + * + */ + trace(message: string): void + + /** + * + */ + unbind(eventName: string): void + + /** + * + */ + enableQE(): void + } + + /** + * + */ + declare class MarkerCollection { + /** + * + */ + readonly numMarkers: number + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + createMarker(time: number): Marker + + /** + * + */ + deleteMarker(marker: Marker): void + + /** + * + */ + getFirstMarker(): Marker + + /** + * + */ + getLastMarker(): Marker + + /** + * + */ + getNextMarker(marker: Marker): Marker + + /** + * + */ + getPrevMarker(marker: Marker): Marker + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class Marker { + /** + * + */ + comments: string + + /** + * + */ + end: Time + + /** + * + */ + readonly guid: string + + /** + * + */ + name: string + + /** + * + */ + start: Time + + /** + * + */ + type: string + + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + getWebLinkFrameTarget(): string + + /** + * + */ + getWebLinkURL(): string + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + setTypeAsChapter(): void + + /** + * + */ + setTypeAsComment(): void + + /** + * + */ + setTypeAsSegmentation(): void + + /** + * + */ + setTypeAsWebLink(url: string, frameTarget: string): void + + /** + * + */ + getColorByIndex(): number + + /** + * + */ + setColorByIndex(index:number): void + + /** + * + */ + unbind(eventName: string): void + } + + /** + * + */ + declare class Document { + /** + * + */ + bind(eventName: string, function_: any): void + + /** + * + */ + getFilePath(): string + + /** + * + */ + importFiles(arg1: any): boolean + + /** + * + */ + setTimeout(eventName: string, function_: any, milliseconds: number): void + + /** + * + */ + unbind(eventName: string): void + } + + /** + * In order to use qe please call app.enableQE() first. + */ + declare const qe: undefined | any + + interface SystemCompatibilityReport { + /** + * @param fullOutputPath The path and filename at which to write the report. + */ + CreateReport(fullOutputPath: string): void + } + + declare const SystemCompatibilityReport: SystemCompatibilityReport; + diff --git a/pype/premiere/extensions/com.pype.avalon/jsx/PypeRename.jsx b/pype/premiere/extensions/com.pype/jsx/PypeRename.jsx similarity index 98% rename from pype/premiere/extensions/com.pype.avalon/jsx/PypeRename.jsx rename to pype/premiere/extensions/com.pype/jsx/PypeRename.jsx index d81e0f497eb..22beb72aa28 100644 --- a/pype/premiere/extensions/com.pype.avalon/jsx/PypeRename.jsx +++ b/pype/premiere/extensions/com.pype/jsx/PypeRename.jsx @@ -357,3 +357,7 @@ if (ExternalObject.AdobeXMPScript === undefined) { // var seq = app.project.activeSequence; // renamer.getSequencePypeMetadata(seq); + +var messageText = 'this module is loaded> PypeRename.jsx'; +$._PPP_.updateEventPanel(messageText); +$.writeln(messageText); diff --git a/pype/premiere/extensions/com.pype/jsx/XMPScript.d.ts b/pype/premiere/extensions/com.pype/jsx/XMPScript.d.ts new file mode 100644 index 00000000000..be64faa069d --- /dev/null +++ b/pype/premiere/extensions/com.pype/jsx/XMPScript.d.ts @@ -0,0 +1,51 @@ +// A commonly used construct for loading XMPScript into +// ExtendScript contexts. +interface ExternalObjectConstructor { + AdobeXMPScript: ExternalObject | undefined; +} + +interface XMPMetaConstructor { + /** Creates an empty object. */ + new (): XMPMetaInstance; + /** + * @param packet A String containing an XML file or an XMP packet. + */ + new (packet: string): XMPMetaInstance; + /** + * @param buffer The UTF-8 or UTF-16 encoded bytes of an XML file + * or an XMP packet. This array is the result of a call to `serializeToArray` + * on an `XMPMeta` instance. + */ + new (buffer: number[]): XMPMetaInstance; + + // Class stuff. +} + +interface XMPMetaInstance { + doesPropertyExist(namespace:String, value:String): Boolean + getProperty(namespace:String, property:String): XMPProperty + setProperty(namespace:String, property:String, value:String): Boolean + countArrayItems(namespace:String, property:String): Number + getArrayItem(namespace:String, property:String, itemIndex:Number): XMPProperty + deleteProperty(namespace:String, property:String): Boolean + appendArrayItem(namespace:String, property:String, arrayOptions:String, valueToAppend:String, valueOptions:String): Boolean + dumpObject():String + serialize(): String + // Instance stuff. +} + +declare const XMPMeta: XMPMetaConstructor | undefined; + +interface XMPConstConstructor { + new (): XMPConstInstance; + NS_DM: string; + NS_DC: string; + ARRAY_IS_ORDERED: string; + // Class stuff. +} + +interface XMPConstInstance { + // Instance stuff. +} + +declare const XMPConst: XMPConstConstructor | undefined; diff --git a/pype/premiere/extensions/com.pype/jsx/batchRenamer.jsx b/pype/premiere/extensions/com.pype/jsx/batchRenamer.jsx new file mode 100644 index 00000000000..483244f3fd7 --- /dev/null +++ b/pype/premiere/extensions/com.pype/jsx/batchRenamer.jsx @@ -0,0 +1,116 @@ +/* global $, JSON, app, XMPMeta, ExternalObject, CSXSEvent, Folder */ +/* -------------------------------------- + -. == [ part 0f PyPE CluB ] == .- +_______________.___._____________________ +\______ \__ | |\______ \_ _____/ + | ___// | | | ___/| __)_ + | | \____ | | | | \ + |____| / ______| |____| /_______ / + \/ \/ + .. __/ CliP R3N4M3R \__ .. +*/ + + +var BatchRenamer = { + + getSelectedVideoTrackItems: function() { + var seq = app.project.activeSequence; + var selected = []; + var videoTracks = seq.videoTracks; + var numOfVideoTracks = videoTracks.numTracks; + + // VIDEO CLIPS IN SEQUENCES + for (var l = 0; l < numOfVideoTracks; l++) { + var videoTrack = seq.videoTracks[l]; + if (videoTrack.isTargeted()) { + $.writeln(videoTrack.name); + // var numOfClips = videoTrack.clips.numTracks; + var numOfClips = videoTrack.clips.numItems; + for (var m = 0; m < numOfClips; m++) { + var clip = videoTrack.clips[m]; + + selected.push({ + name: clip.name, + clip: clip, + sequence: seq, + videoTrack: videoTrack + }); + } + } + } + var names = []; + var items = {}; + var sorted = []; + for (var c = 0; c < selected.length; c++) { + items[selected[c].name] = selected[c]; + names.push(selected[c].name); + } + names.sort(); + + for (var cl = 0; cl < names.length; cl++) { + sorted.push(items[names[cl]]); + } + return sorted; + }, + + renameTargetedTextLayer: function (data) { + $.bp(true); + $.writeln(data); + var selected = BatchRenamer.getSelectedVideoTrackItems(); + + var seq = app.project.activeSequence; + var metadata = $.pype.getSequencePypeMetadata(seq, true); + + var startCount = 10; + var stepCount = 10; + var padding = 3; + var newItems = {}; + var episode = data.ep; + var episodeSuf = data.epSuffix; + var shotPref = 'sh'; + var count = 0; + var seqCheck = ''; + + for (var c = 0; c < selected.length; c++) { + // fill in hierarchy if set + var parents = []; + var hierarchy = []; + var name = selected[c].name; + var sequenceName = name.slice(0, 5); + var shotNum = Number(name.slice((name.length - 3), name.length)); + + // if (sequenceName !== seqCheck) { + // seqCheck = sequenceName; + // count = 0; + // }; + // + // var seqCount = (count * stepCount) + startCount; + // count += 1; + + var newName = episode + sequenceName + shotPref + (shotNum).pad(padding); + $.pype.log(newName); + selected[c].clip.name = newName; + + parents.push({ + 'entityType': 'Episode', + 'entityName': episode + '_' + episodeSuf + }); + hierarchy.push(episode + '_' + episodeSuf); + + parents.push({ + 'entityType': 'Sequence', + 'entityName': episode + sequenceName + }); + hierarchy.push(episode + sequenceName); + + newItems[newName] = { + 'parents': parents, + 'hierarchy': hierarchy.join('/') + }; + } + + metadata.clips = newItems; + $.pype.setSequencePypeMetadata(seq, metadata); + return JSON.stringify(metadata); + } +} \ No newline at end of file diff --git a/pype/premiere/extensions/com.pype/jsx/extendscript.d.ts b/pype/premiere/extensions/com.pype/jsx/extendscript.d.ts new file mode 100644 index 00000000000..0c473bd4cb0 --- /dev/null +++ b/pype/premiere/extensions/com.pype/jsx/extendscript.d.ts @@ -0,0 +1,2708 @@ +/** + * The $ object provides a number of debugging facilities and informational methods. + */ +interface $ { + /** + * The ExtendScript build information. + */ + readonly build: string + + /** + * The ExtendScript build date. + */ + readonly buildDate: Date + + /** + * The character used as the decimal point character in formatted numeric output. + */ + decimalPoint: string + + /** + * The name of the current ExtendScript engine, if set. + */ + readonly engineName: string + + /** + * The most recent run-time error information. + * Assigning error text to this property generates a run-time error; however, the preferred way to generate a run-time error is to throw an Error object. + */ + error: Error + + /** + * The file name of the current script. + */ + readonly fileName: string + + /** + * Gets or sets low-level debug output flags. + * A logical AND of bit flag values: + * 0x0002 (2): Displays each line with its line number as it is executed. + * 0x0040 (64): Enables excessive garbage collection. Usually, garbage collection starts when the number of objects has increased by a certain amount since the last garbage collection. This flag causes ExtendScript to garbage collect after almost every statement. This impairs performance severely, but is useful when you suspect that an object gets released too soon. + * 0x0080 (128): Displays all calls with their arguments and the return value. + * 0x0100 (256): Enables extended error handling (see strict). + * 0x0200 (512): Enables the localization feature of the toString method. Equivalent to the localize property. + */ + flags: number + + /** + * A reference to the global object, which contains the JavaScript global namespace. + */ + readonly global: any + + /** + * A high-resolution timer, measuring the time in microseconds. The timer starts when ExtendScript is + * initialized during the application startup sequence. Every read access resets the timer to Zero. + */ + readonly hiresTimer: number + + /** + * The path for include files for the current script. + */ + readonly includePath: string + + /** + * The current debugging level, which enables or disables the JavaScript debugger. + * One of 0 (no debugging), 1 (break on runtime errors), or 2 (full debug mode). + */ + level: number + + /** + * The current line number of the currently executing script. + */ + readonly line: number + + /** + * Gets or sets the current locale. + * The string contains five characters in the form LL_RR, where LL is an ISO 639 language specifier, and RR is an ISO 3166 region specifier.Initially, this is the value that the application or the platform returns for the current user. You can set it to temporarily change the locale for testing. To return to the application or platform setting, set to undefined, null, or the empty string. + */ + locale: string + + /** + * Set to true to enable the extended localization features of the built-in toString() method. + */ + localize: boolean + + /** + * The ExtendScript memory cache size, in bytes. + */ + memCache: number + + /** + * The current operating system version information. + */ + readonly os: string + + /** + * An array of objects containing information about the display screens attached to your computer. + * Each object has the properties left, top, right, bottom, which contain the four corners of each screen in global coordinates.A property primary is true if that object describes the primary display. + */ + readonly screens: object[] + + /** + * The current stack trace. + */ + readonly stack: string + + /** + * Sets or clears strict mode for object modification. + * When true, any attempt to write to a read-only property causes a runtime error. Some objects do not permit the creation of new properties when true. + */ + strict: any + + /** + * The version number of the ExtendScript engine. + * Formatted as a three-part number and description; for example: "3.92.95 (debug)". + */ + readonly version: string + + /** + * Shows an About box for the ExtendScript component, and returns the text for the box. + */ + about(): string + + /** + * Breaks execution at the current position. + * @param condition A string containing a JavaScript statement to be used as a condition. If the statement evaluates to true or nonzero when this point is reached, execution stops. + */ + bp(condition?: any): void + + /** + * Invokes the platform-specific color selection dialog, and returns the selected color. + * @param color The color to be preselected in the dialog, as 0xRRGGBB, or -1 for the platform default. + */ + colorPicker(color: number): number + + /** + * Loads and evaluates a file. + * @param file The file to load. + * @param timeout An optional timeout in milliseconds. + */ + evalFile(file: File, timeout?: number): any + + /** + * Initiates garbage collection in the ExtendScript engine. + */ + gc(): void + + /** + * Retrieves the value of an environment variable. + * @param name The name of the variable. + */ + getenv(name: string): string + + /** + * Sets the value of an environment variable. + * @param name The name of the variable. + * @param value The value of the variable. + */ + setenv(name: string, value: string): void + + /** + * Suspends the calling thread for a number of milliseconds. + * During a sleep period, checks at 100 millisecond intervals to see whether the sleep should be terminated. This can happen if there is a break request, or if the script timeout has expired. + * @param msecs Number of milliseconds to sleep. + */ + sleep(msecs: number): void + + /** + * Converts this object to a string. + */ + toString(): string + + /** + * Prints text to the Console. + * @param text The text to print. All arguments are concatenated. + */ + write(text: any): void + + /** + * Prints text to the Console, and adds a newline character. + * @param text The text to print. All arguments are concatenated. + */ + writeln(text: any): void + } + declare const $: $ + + interface ObjectConstructor { + readonly prototype: Object + + /** + * Creates and returns a new object of a given type. + * @param what The object type. + */ + new (what: any): Object + (): any + (what: any): any + + /** + * Reports whether an object is still valid. + * @param what The object to check. + */ + isValid(what: Object): boolean + } + declare const Object: ObjectConstructor + + /** + * The base class of all JavaScript objects. + */ + interface Object { + /** + * Points to the constructor function that created this object. + * Note that this property is treated as an XML element in the XML class. + */ + readonly constructor: Function + + /** + * Points to the prototype object for this object. + * Note that this property is treated as an XML element in the XML class. + */ + readonly prototype: Object + + /** + * Retrieves and returns the Reflection object associated with this method or a property. + * Note that this property is treated as an XML element in the XML class. + */ + readonly reflect: Reflection + + /** + * Reports whether a given property is defined with an instance or within the prototype chain. + * @param name The name of the property to check. + */ + hasOwnProperty(name: string): boolean + + /** + * Checks whether the given object is a prototype of this object. + * @param what The object to check. + */ + isPrototypeOf(what: Object): boolean + + /** + * Reports whether a given property is enumerable. + * @param name The name of the property to check. + */ + propertyIsEnumerable(name: string): boolean + + /** + * Creates and returns a string representing this object, localized for the current locale. See toString(). + */ + toLocaleString(): string + + /** + * Creates and returns a string representation of this object. + * This function serializes the object, so that it can, for example, be passed between engines. Pass the returned string back to eval() to recreate the object. Works only with built-in classes. + */ + toSource(): string + + /** + * Creates and returns a string representing this object. + * Many objects (such as Date) override this method in favor of their own implementation. If an object has no string value and no user-defined toString() method, the default method returns [object type], where type is the object type or the name of the constructor function that created the object. + */ + toString(): string + + /** + * Removes the watch function of a property. + * @param name The name of the property to unwatch. + */ + unwatch(name: string): void + + /** + * Retrieves and returns the primitive value of this object. + * If the object has no primitive value, returns the object itself.Note that you rarely need to call this method yourself.The JavaScript interpreter automatically invokes it when encountering an object where a primitive value is expected. + */ + valueOf(): Object + + /** + * Adds a watch function to a property, which is called when the value changes. + * This function can accept, modify, or reject a new value that the user, application, or a script has attempted to place in a property. + * @param name The name of the property to watch. + * @param func The function to be called when the value of this property changes. This function must three arguments, and return as its result the value to be stored in the property. The arguments are: name: the name of the property that changes. oldValue: The old property value. newValue: The new property value that was specified. + */ + watch(name: string, func: Function): void + } + + interface ArrayConstructor { + readonly prototype: Array + + /** + * Creates and returns a new array. + * Takes any number of parameters, which become the elements of the array, or a single value which becomes the length of an empty array. Note that you cannot create a one-element array, as the single parameter value is interpreted as the length. Returns the new array. + * @param arrayLength If no other parameters are passed, the initial length of the empty array. Otherwise, the first element. + * @param values If there is more than one parameter, the array is initialized with the given parameters. + */ + new (arrayLength?: number): any[] + new (arrayLength: number): T[] + new (...values: T[]): T[] + (arrayLength?: number): any[] + (arrayLength: number): T[] + (...values: T[]): T[] + } + declare const Array: ArrayConstructor + + /** + * An array with integer indexing and a length property. + */ + interface Array { + [n: number]: T + + /** + * The length of the array + */ + length: number + + /** + * Returns a new array created by concatenating the given values to the end of the original array. + * The original array is unchanged.If an array is provided as a parameter to concat(), each of its elements are appended as separate array elements at the end of the new array.Returns a new array, the result of concatenation the given values to the end of the original array. + * @param values Any number of values to be added to the end of the array. Can also be arrays. + */ + concat(...values: T[][]): T[] + + /** + * Joins all elements of the array into a string; optionally, each element is separated by delimiter. + * Returns the string containing the joined elements and delimiters. + * @param delimiter A string used to separate each element of the array. If omitted, the array elements are separated with a comma. + */ + join(delimiter?: string): string + + /** + * Removes the last element from the array, decreases the length by 1, and returns the value of the element. + * Returns the value of the deleted array element. + */ + pop(): T | undefined + + /** + * Places one or more values onto the end of the array and increases length by n. + * Returns the new length of the array. + * @param values Any number of values to be pushed onto the end of the array. + */ + push(...values: T[]): number + + /** + * Reverses the order of the elements in the array. + * Returns the reversed array. + */ + reverse(): T[] + + /** + * Removes the first element from the array, decreases the length by 1, and returns the value of the element. + * Returns the value of the deleted array element. + */ + shift(): T | undefined + + /** + * Creates a new array, which contains a subset of the original array's elements. + * The slice begins with the index start, and continues up to, but not including the index, end.If start or end is a negative number, the indexed is resolved counting backwards from the end of the array resulting in the element array[array. length + negativeIndex]. Returns a new array containing elements array[start] through array[end-1]. + */ + slice(start?: number, end?: number): T[] + + /** + * Sorts the elements of the array in place, using the given function to compare to elements. + * If no function is provided, the elements are sorted alphabetically.Returns no return value. + * @param userFunction A user-supplied function of the form userFunction(a, b) which returns less than 0 if a is greater than b, 0 if a and b are equal, and greater than 0 if b is greater than a. + */ + sort(userFunction?: (a: T, b: T) => number): this + + /** + * Removes num elements from the array beginning with index, start. + * Optionally insert new elements beginning at index start.To ensure contiguity, elements are moved up to fill in any gaps.Returns a new array containing any elements deleted from the original array. + * @param start The index of the first element to remove. Negative values are relative to the end of the array. + * @param deleteCount The number of array elements to remove, including start. If omitted, all elements from array index start to the end of the array are removed. + * @param values A list of one or more values to be added to the array starting at index start. Must specify a value for num, to use this argument. + */ + splice(start: number, deleteCount?: number, ...values: T[]): T[] + + /** + * Converts an array to a string and returns the string (localized). + */ + toLocaleString(): string + + /** + * Creates a string representation of this object that can be fed back to eval() to re-create an object. Works only with built-in classes. + */ + toSource(): string + + /** + * Converts an array to a string and returns the string. + * Yields the same result as array. join() when called without a parameter.Returns a comma-separated list of all the elements of the array. + */ + toString(): string + + /** + * Adds one or more elements to the beginning of the array. + * Returns the new array length. + * @param values The values of one or more elements to be added to the beginning of the array. + */ + unshift(...values: T[]): number + } + + /** + * A global object containing a set of math functions and constants. + */ + interface Math { + /** + * Euler's constant and the base of natural logarithms. + */ + readonly E: number + + /** + * The natural logarithm of 10. + */ + readonly LN10: number + + /** + * The natural logarithm of 2. + */ + readonly LN2: number + + /** + * The base 10 logarithm of e. + */ + readonly LOG10E: number + + /** + * The base 2 logarithm of e. + */ + readonly LOG2E: number + + /** + * The ratio of the circumference of a circle to its diameter. + */ + readonly PI: number + + /** + * The reciprocal of the square root of 1/2. + */ + readonly SQRT1_2: number + + /** + * The square root of 2. + */ + readonly SQRT2: number + + /** + * Returns the absolute value of a number. + * @param x A number. + */ + abs(x: number): number + + /** + * Returns the arc cosine(in radians) of a number. + * @param x A number. + */ + acos(x: number): number + + /** + * Returns the arc sin(in radians) of a number. + * @param x A number. + */ + asin(x: number): number + + /** + * Returns the arc tangent(in radians) of a number. + * @param x A number. + */ + atan(x: number): number + + /** + * Returns the arc tangent of the quotient of its arguments (y/x). + * @param y A number. + * @param x A number. + */ + atan2(y: number, x: number): number + + /** + * Rounds the number up to the nearest integer. + * @param x A number. + */ + ceil(x: number): number + + /** + * Returns the cosine of an angle provided in radians. + * @param x An angle, in radians. + */ + cos(x: number): number + + /** + * Returns Math.E raised to the power of a number. + * @param x A number. + */ + exp(x: number): number + + /** + * Rounds a number down to the nearest integer. + * @param x A number. + */ + floor(x: number): number + + /** + * Returns the natural logarithm of a number. + * @param x A number. + */ + log(x: number): number + + /** + * Returns the largest of zero or more numbers. + * @param rest Numbers. + */ + max(...rest: number[]): number + + /** + * Returns the smallest of zero or more numbers. + * @param rest Numbers. + */ + min(...rest: number[]): number + + /** + * Returns x raised to the power of y. + * @param x Numbers. + * @param y + */ + pow(x: number, y: number): number + + /** + * Returns a pseudo-random number from 0.0 up to but not including 1.0. + */ + random(): number + + /** + * Rounds a number to the nearest integer. + * @param x A number. + */ + round(x: number): number + + /** + * Returns the sine of an angle provided in radians. + * @param x An angle, in radians. + */ + sin(x: number): number + + /** + * Returns the square root of a number. + * @param x A number. + */ + sqrt(x: number): number + + /** + * Returns the tangent of an angle provided in radians. + * @param x An angle, in radians. + */ + tan(x: number): number + } + declare const Math: Math + + interface DateConstructor { + readonly prototype: Date + + /** + * Returns a new Date object holding the current date and time. + * If parameters are supplied, returns a new Date object holding the supplied date and time. + * @param year The year expressed in four digits. + * @param month An integer value from 0 (Jan) to 11 (Dec). + * @param day An integer value from 1 to 31, If this argument is not supplied, its value is set to 0. + * @param hours An integer value from 0 (midnight) to 23 (11 PM). If this argument is not supplied, its value is set to 0. + * @param min An integer value from 0 to 59. If this argument is not supplied, its value is set to 0. + * @param sec An Integer value from 0 to 59. If this argument is not supplied, its value is set to 0. + * @param ms An integer value from 0 to 999. If this argument is not supplied, its value is set to 0. + */ + new (): Date + new (value: number): Date + new (value: string): Date + new ( + year: number, + month: number, + day?: number, + hours?: number, + min?: number, + sec?: number, + ms?: number, + ): Date + + /** + * Parses a string, returning a new Date object. The string should be similar to the string returned bt toString(). + * @param text The string to parse. + */ + parse(text: string): Date + + /** + * Returns the number of milliseconds between midnight January 1, 1970, UTC, and the specified time. + * @param year The year expressed in four digits, for example, 2001. To indicate for a year from 1900 to 1999, you can specify a value from 0 to 99. + * @param month An integer value from 0 (Jan) to 11 (Dec). + * @param day An integer value from 1 to 31, If this argument is not supplied, its value is set to 0. + * @param hours An integer value from 0 (midnight) to 23 (11 PM). If this argument is not supplied, its value is set to 0. + * @param min An integer value from 0 to 59. If this argument is not supplied, its value is set to 0. + * @param sec An Integer value from 0 to 59. If this argument is not supplied, its value is set to 0. + * @param ms An integer value from 0 to 999. If this argument is not supplied, its value is set to 0. + */ + UTC( + year: number, + month?: number, + day?: number, + hours?: number, + min?: number, + sec?: number, + ms?: number, + ): Date + } + declare const Date: DateConstructor + + /** + * A date/time object. + */ + interface Date { + /** + * Returns the day of the month of the specified Date object in local time. + */ + getDate(): number + + /** + * Returns the day of the week for the specified Date object in local time. + * This is an integer from 0 (Sunday) to 6 (Saturday).Returns the day of the week for date. + */ + getDay(): number + + /** + * Returns the four digit year of the specified Date object in local time. + */ + getFullYear(): number + + /** + * Returns the hour of the specified Date object in local time. + */ + getHours(): number + + /** + * Returns the milliseconds of the specified Date object in local time. + */ + getMilliseconds(): number + + /** + * Returns the minutes of the specified Date object in local time. + */ + getMinutes(): number + + /** + * Returns the month of the specified Date object in local time. + */ + getMonth(): number + + /** + * Returns the seconds of the specified Date object in local time. + */ + getSeconds(): number + + /** + * Returns the number of milliseconds since midnight January 1,1970 UTC for the specified Date object. + */ + getTime(): number + + /** + * Returns the difference in minutes between the computer's local time and UTC. + */ + getTimezoneOffset(): number + + /** + * Returns the day of the month of the specified Date object according to UTC. + */ + getUTCDate(): number + + /** + * Returns the day of the week for the specified Date object according to UTC. + */ + getUTCDay(): number + + /** + * Returns the four digit year of the specified Date object according to UTC. + */ + getUTCFullYear(): number + + /** + * Returns the hour of the specified Date object according to UTC. + */ + getUTCHours(): number + + /** + * Returns the milliseconds of the specified Date object according to UTC. + */ + getUTCMilliseconds(): number + + /** + * Returns the minutes of the specified Date object according to UTC. + */ + getUTCMinutes(): number + + /** + * Returns the month of the specified Date object according to UTC. + */ + getUTCMonth(): number + + /** + * Returns the seconds of the specified Date object according to UTC. + */ + getUTCSeconds(): number + + /** + * Returns the year of the specified Date object, as a difference from 1900, in local time. + */ + getYear(): number + + /** + * Sets the day of the month of a specified Date object according to local time. + * Returns the number of milliseconds between the new date and midnight, January 1, 1970. + * @param date An integer from 1 to 31 indicating the day of the month. + */ + setDate(date: number): number + + /** + * Sets the year of a specified Date object according to local time. + * This method can also set month and date if those arguments are specified. Returns the number of milliseconds between the new date and midnight, January 1, 1970. + * @param year A four-digit integer value indicating the year to set. + */ + setFullYear(year: number): number + + /** + * Sets the hours of a specified Date object according to local time. + * Returns the number of milliseconds between the new date and midnight, January 1, 1970. + * @param hour An integer value from 0 (midnight) to 23 (11 PM). + */ + setHours(hour: number): number + + /** + * Sets the milliseconds of a specified Date object according to local time. + * Returns the number of milliseconds between the new date and midnight, January 1, 1970. + * @param ms An integer value from 0 to 999. + */ + setMilliseconds(ms: number): number + + /** + * Sets the minutes of a specified Date object according to local time. + * Returns the number of milliseconds between the new date and midnight, January 1, 1970. + * @param minutes An integer value from 0 to 59. + */ + setMinutes(minutes: number): number + + /** + * Sets the month of a specified Date object according to local time. + * Returns the number of milliseconds between the new date and midnight, January 1, 1970. + * @param month An integer value from 0 (Jan) to 11 (Dec). + */ + setMonth(month: number): number + + /** + * Sets the seconds of a specified Date object according to local time. + * Returns the number of milliseconds between the new date and midnight, January 1, 1970. + * @param seconds An integer value from 0 to 59. + */ + setSeconds(seconds: number): number + + /** + * Sets the date of a specified Date object in milliseconds since midnight, January 1, 1970. + * Returns the value of ms. + * @param ms An integer indicating the number of milliseconds between the date set and midnight, January 1, 1970. + */ + setTime(ms: number): number + + /** + * Sets the date of a specified Date object according to universal time. + * Returns the number of milliseconds between the new date and midnight, January 1, 1970 in UTC time. + * @param date An integer from 1 to 31 indicating the day of the month. + */ + setUTCDate(date: number): number + + /** + * Sets the year of a specified Date object according to UTC, can also set the month and date. + * Returns the number of milliseconds between the date set and midnight, January 1, 1970, in UTC. + * @param year The year expressed in four digits. + */ + setUTCFullYear(year: number): number + + /** + * Sets the hours of a specified Date object according to UTC. + * Returns the number of milliseconds between the date set and midnight, January 1, 1970, in UTC. + * @param hours An integer value from 0 (midnight) to 23 (11 PM) indicating the hour to be set. + */ + setUTCHours(hours: number): number + + /** + * Sets the milliseconds of a specified Date object according to UTC. + * Returns the number of milliseconds between the date set and midnight, January 1, 1970, in UTC. + * @param ms An integer value in the range of 0 to 999 indicating the number of milliseconds to set. + */ + setUTCMilliseconds(ms: number): number + + /** + * Sets the minutes of a specified Date object according to UTC. + * Returns the number of milliseconds between the date set and midnight, January 1, 1970, in UTC. + * @param min An integer value in the range 0 to 59 indicating the number of minutes to be set. + */ + setUTCMinutes(min: number): number + + /** + * Sets the month of a specified Date object according to UTC. + * Returns the number of milliseconds between the date set and midnight, January 1, 1970, in UTC. + * @param month An integer value in the range 0 (Jan.) to 11 (Dec.) indicating the month to set. + */ + setUTCMonth(month: number): number + + /** + * Sets the seconds of a specified Date object according to UTC. + * Returns the number of milliseconds between the date set and midnight, January 1, 1970, in UTC. + * @param sec An integer value in the range 0 to 59 indicating the number of seconds to set. + */ + setUTCSeconds(sec: number): number + + /** + * Sets the year of a specified Date object according to local time, as a difference between the current year and 1900. + * Returns the number of milliseconds between the date set and midnight, January 1, 1970. + * @param year An integer value indicating the year to set. The method interprets a 1- or 2- digit value to mean the 1900s; for example, 13 is interpreted to mean 1913. + */ + setYear(year: number): number + + /** + * Returns the date as a string. + */ + toDateString(): string + + /** + * Returns the date and time adjusted to GMT (UTC) as a string. + */ + toGMTString(): string + + /** + * Returns the date as a localized string. + */ + toLocaleDateString(): string + + /** + * Returns a string value representing the date and time stored in the Date object in human readable format (localized). + */ + toLocaleString(): string + + /** + * Returns the time as a localized string. + */ + toLocaleTimeString(): string + + /** + * Creates a string representation of this object that can be fed back to eval() to re-create an object. Works only with built-in classes. + */ + toSource(): string + + /** + * Returns a string value representing the date and time stored in the Date object in human readable format. + * Returns the following string is an example of the format returned by this method: Mon Aug 13, 10:54:21 GMT-0700 2001. + */ + toString(): string + + /** + * Returns the time as a string. + */ + toTimeString(): string + + /** + * Returns the date and time adjusted to UTC as a string. + */ + toUTCString(): string + + /** + * The valueOf() method returns the number of milliseconds that have passed since midnight, Returns an integer. + */ + valueOf(): number + } + + interface FunctionConstructor { + readonly prototype: Function + + /** + * The Function constructor parses the argument list and creates a Function object. + * @param arguments The list of formal arguments, separated by commas. The formal arguments can also be supplied one by one; in this case, the last argument to the Function constructor is considered to be the function body. + * @param body The body of the function to create. + */ + new (arguments: string, body: string): Function + (arguments: string, body: string): Function + } + declare const Function: FunctionConstructor + + /** + * Wraps a built-in or JavaScript function. + */ + interface Function { + /** + * The function arguments, packed into an array. + * This property is deprecated; use the arguments property within the function body. + */ + arguments: object + + /** + * The number of formal arguments. + * This property is deprecated; use the length property instead. + */ + readonly arity: number + + /** + * The number of formal arguments. + */ + readonly length: number + + /** + * The function name. + */ + readonly name: string + + /** + * Apply a this object and an argument list to a function. + * This function is different from call(); here, the arguments are suppliedas an Array object. + * @param thisObj The object to be used as this. + * @param args An array of arguments. + */ + apply(thisObj: object, args: any): any + + /** + * Apply a this object and arguments to a function. + * This function is different from apply(); here, the arguments are supplied one by one. + * @param thisObj The object to be used as this. + * @param arguments The first agument to the function. Add as many as needed. + */ + call(thisObj: object, ...arguments: any[]): any + + /** + * Creates a string representation of this object that can be fed back to eval() to re-create an object. Works only with JavaScript functions. + */ + toSource(): string + + /** + * Returns the function definition as a string. + */ + toString(): string + } + + interface StringConstructor { + readonly prototype: String + + /** + * Returns a string representation of the value given as an argument. + * @param value A number, variable, or object to convert to a string. + */ + new (value?: any): String + (value: any): string + + /** + * Returns a string created by concatenation one or more characters specified as ASCII values. + * @param value1 One or more ASCII values. + */ + fromCharCode(value1: number): string + } + declare const String: StringConstructor + + /** + * A character string. Each character is adressable by index. + */ + interface String { + /** + * The length of the string. + */ + readonly length: number + + /** + * Get character at index. + */ + readonly [index: number]: string + + /** + * Returns a string consisting of this string enclosed in a tag. + * @param name The text to be stored in the anchors' name attribute. + */ + anchor(name: string): string + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + big(): string + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + blink(): string + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + bold(): string + + /** + * Returns the character at the specified index. + * @param index An integer between 0 and string.length -1, specifying the character to return. + */ + charAt(index: number): string + + /** + * Returns the Unicode value of the character at the given index. + * @param index An integer between 0 and string.length -1, specifying the character. + */ + charCodeAt(index: number): number + + /** + * If necessary, converts the one or more given values to strings. + * Those values are concatenated with the original string, the result is returned. The original string is not effected.Returns the concatenated string. + * @param value The values to be concatenated with the given string. + */ + concat(value: string): string + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + fixed(): string + + /** + * Returns a string consisting of this string enclosed in a tag. + * @param color The value to be stored in the tag's color attribute. + */ + fontcolor(color: string): string + + /** + * Returns a string consisting of this string enclosed in a tag. + * @param size The value to be stored in the tag's size attribute. + */ + fontsize(size: number): string + + /** + * Returns the index within the string of the first occurrence of the specified string, starting the search at fromIndex if provided. + * @param searchValue The string for which to search. + * @param offset The starting offset of the search. + */ + indexOf(searchValue: string, offset?: number): number + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + italics(): string + + /** + * Returns the index within the string of the last occurrence of the specified value. + * The string is searched backward, starting at fromIndex.Returns the index within the string where the last occurrence of searchValue was found, or -1 if it was not found. + * @param searchValue The string for which to search. + * @param offset The starting offset of the search. + */ + lastIndexOf(searchValue: string, offset?: number): number + + /** + * Returns a string consisting of this string enclosed in a tag. + * @param href The value to be stored in the tag's href attribute. + */ + link(href: string): string + + /** + * Performs a localized comparison of two strings. + * @param what The string to compare with. + */ + localeCompare(what: string): number + + /** + * Matches a string against a regular expression. + * @param regexp The regular expression to use. + */ + match(regexp: RegExp | string): RegExpMatchArray | null + + /** + * + * @param what + * @param with_ + */ + replace(what: any, with_: string): string + + /** + * + * @param search + */ + search(search: RegExp): number + + /** + * Extracts a substring of the given string and returns it as a new string. + * The substring begins at startSlice, and includes all characters up to, but not including the character at the index endSlice. A negative value indexes from the end of the string.For example, a negative value for startSlice is resolved as: string. length + startSlice.The original string is unchanged.Returns a substring of characters from the given string, starting at startSlice and ending with endSlice-1. + * @param startSlice The index at which to begin extraction. + * @param endSlice The index at which to end extraction. If omitted, slice extracts to the end of the string. + */ + slice(startSlice: number, endSlice?: number): string + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + small(): string + + /** + * Splits a string into a group of substrings, places those strings in an array, and returns the array. + * The substrings are created by breaking the original string at places that match delimiter, the delimiter characters are removed.Returns an array whose elements are the substrings. + * @param delimiter Specifies the string to use for delimiting. If delimiter is omitted, the array returned contains one element, consisting of the entire string. + * @param limit + */ + split(delimiter: string, limit?: number): string[] + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + strike(): string + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + sub(): string + + /** + * Returns a string containing the characters beginning at the specified index, start, through the specified number of characters. + * The original string is unchanged.Returns a string containing the extracted characters. + * @param start Location at which to begin extracting characters. + * @param length The number of characters to extract. + */ + substr(start: number, length?: number): string + + /** + * Returns a substring of the given string by extracting characters from indexA up to but not including indexB. + * The original string is unchanged.Returns a substring of characters from the given string, starting at indexA and ending with indexB-1. + * @param indexA The index to begin extracting. + * @param indexB The index at which to end extraction. If omitted, slice extracts to the end of the string. + */ + substring(indexA: number, indexB?: number): string + + /** + * Returns a string consisting of this string enclosed in a tag. + */ + sup(): string + + /** + * Returns a new string which contains all the characters of the original string converted to lowercase (localized). + * The original string is unchanged. + */ + toLocaleLowerCase(): string + + /** + * Returns a new string which contains all the characters of the original string converted to uppercase (localized). + * The original string is unchanged. + */ + toLocaleUpperCase(): string + + /** + * Returns a new string which contains all the characters of the original string converted to lowercase. + * The original string is unchanged. + */ + toLowerCase(): string + + /** + * Creates a string representation of this object that can be fed back to eval() to re-create an object. Works only with built-in classes. + */ + toSource(): string + + /** + * Returns itself. + */ + toString(): string + + /** + * Returns a new string which contains all the characters of the original string converted to uppercase. + * The original string is unchanged. + */ + toUpperCase(): string + + /** + * The valueOf() method returns the number of milliseconds that have passed since midnight, Returns an integer. + */ + valueOf(): string + } + + interface NumberConstructor { + readonly prototype: Number + + /** + * Returns a new Number object set to the value of the argument converted to a number. + * @param value The value of the object being created. + */ + new (value?: any): Number + (value: any): number + + /** + * A constant representing the largest representable number. + */ + readonly MAX_VALUE: number + + /** + * A constant representing the smallest representable number. + */ + readonly MIN_VALUE: number + + /** + * A constant representing negative infinity. + */ + readonly NEGATIVE_INFINITY: number + + /** + * A constant representing the special "Not a Number" value. + */ + readonly NaN: number + + /** + * A constant representing positive infinity. + */ + readonly POSITIVE_INFINITY: number + } + declare const Number: NumberConstructor + + /** + * Wraps a numeric value. + */ + interface Number { + /** + * Converts the Number object to a string in scientific notation. + * @param decimals The number of decimals. + */ + toExponential(decimals: number): string + + /** + * Converts the Number object to a string with fixed decimals. + * @param decimals The number of decimals. + */ + toFixed(decimals: number): string + + /** + * Returns the value of a Number object converted to a string, using localized conventions. + */ + toLocaleString(): string + + /** + * Converts the Number object to a string in either scientific or fixed notation, epending on its value. + * @param decimals The number of decimals. + */ + toPrecision(decimals: number): string + + /** + * Creates a string representation of this object that can be fed back to eval() to re-create an object. Works only with built-in classes. + */ + toSource(): string + + /** + * Returns the value of a Number object converted to a string. + * @param radix The optional conversion radix. + */ + toString(radix?: number): string + + /** + * Returns the value of a Number object as a primitive number. + */ + valueOf(): number + } + + interface BooleanConstructor { + readonly prototype: Boolean + + /** + * Creates and returns a new Boolean object set to the value of the argument converted to a boolean. + * @param value The value to be converted to a Boolean. + */ + new (value?: any): Boolean + (value: any): boolean + } + declare const Boolean: BooleanConstructor + + /** + * Wraps a Boolean value. + */ + interface Boolean { + /** + * Creates a string representation of this object that can be fed back to eval() to re-create an object. Works only with built-in classes. + */ + toSource(): string + + /** + * Returns the string representation of the value of bool. + * The method returns the string true if the primitive value of bool is true; otherwise it returns the string false. + */ + toString(): string + + /** + * Returns the primitive value of bool. + * The method returns true if the primitive value of bool is true; otherwise it returns false. + */ + valueOf(): boolean + } + + interface RegExpConstructor { + readonly prototype: RegExp + + /** + * Creates and returns a new RegExp object set to the value of the argument converted to a regular expression. + * @param pattern The pattern to convert. + * @param flags Flags that control how the conversion is performed. A string containing any combination of the letters i, m, g: "i" -- ignore case in pattern matching "m" -- treat the string as multiple lines "g" -- do global pattern matching + */ + new (pattern: string | RegExp, flags?: string): RegExp + (pattern: string | RegExp, flags?: string): RegExp + + /** + * The matched subexpression #1. + */ + readonly $1: string + + /** + * The matched subexpression #2. + */ + readonly $2: string + + /** + * The matched subexpression #3. + */ + readonly $3: string + + /** + * The matched subexpression #4. + */ + readonly $4: string + + /** + * The matched subexpression #5. + */ + readonly $5: string + + /** + * The matched subexpression #6. + */ + readonly $6: string + + /** + * The matched subexpression #7. + */ + readonly $7: string + + /** + * The matched subexpression #8. + */ + readonly $8: string + + /** + * The matched subexpression #9. + */ + readonly $9: string + + /** + * Indicates whether the match is a global match. + */ + global: boolean + + /** + * Indicates whether the match is not case sensitive. + */ + ignoreCase: boolean + + /** + * The original input string. + */ + input: string + + /** + * The last match. + */ + readonly lastMatch: string + + /** + * The value of the last matched subexpression. + */ + readonly lastParen: string + + /** + * The string before the match. + */ + readonly leftContext: string + + /** + * Indicates whether the match matches multiple lines. + */ + multiline: boolean + + /** + * The string after the match. + */ + readonly rightContext: string + } + declare const RegExp: RegExpConstructor + + /** + * Wraps a regular expression. + */ + interface RegExp { + /** + * Compiles a string to a regular expression. Returns true if the compilation was successful. + * @param pattern The pattern to compile. + */ + compile(pattern: string): boolean + + /** + * Execute a regular expression. + * The return value is an array of matches, with the first element containing the match, and successive elements containing the results of any matching subexpression in their order of appearance. If there is no match, the result is null. + * @param text The string to match. + */ + exec(text: string): RegExpExecArray | null + + /** + * Execute a regular expression, and return true if there is a match. + * @param text The string to match. + */ + test(text: string): boolean + + /** + * Converts this RegExp object to a string. + */ + toString(): string + } + + interface RegExpMatchArray extends Array { + index?: number + input?: string + } + + interface RegExpExecArray extends Array { + index: number + input: string + } + + interface ErrorConstructor { + readonly prototype: Error + + /** + * Creates a new Error object. + * @param msg The error message. + * @param file The name of the file. + * @param line The line number. + */ + new (msg: string, file?: string, line?: number): Error + (msg: string, file?: string, line?: number): Error + } + declare const Error: ErrorConstructor + + /** + * Wraps a runtime error. + */ + interface Error { + /** + * The error message. + */ + description: string + + /** + * Creates a string representation of this object that can be fed back to eval() to re-create an object. Works only with built-in classes. + */ + toSource(): string + + /** + * Convert this object to a string. + */ + toString(): string + } + + interface FileConstructor { + readonly prototype: File + + /** + * Creates and returns a new File object referring to a given file system location. + * @param path The full or partial path name of the file,in platform-specific or URI format. The value stored in the object is the absolute path. The file that the path refers to does not need to exist.If the path refers to an existing folder: The File function returns a Folder object instead of a File object. The new operator returns a File object for a nonexisting file with the same name. + */ + new (path?: string): File + (path?: string): File + + /** + * The name of the file system. + * This is a class property accessed through the File constructor. Valid values are "Windows", "Macintosh", and "Unix". + */ + readonly fs: string + + /** + * Decodes a UTF-8 encoded string as required by RFC 2396, and returns the decoded string. + * See also String.decodeURI(). + * @param uri The UTF-8 encoded string to decode. + */ + decode(uri: string): string + + /** + * Encodes a string as required by RFC 2396, and returns the encoded string. + * All special characters are encoded in UTF-8 and stored as escaped characters starting with the percent sign followed by two hexadecimal digits. For example, the string "my file" is encoded as "my%20file". + * Special characters are those with a numeric value greater than 127, except the following: / - _ . ! ~ * ' ( ) + * See also encodeURI(). + * @param name The string to encode. + */ + encode(name: string): string + + /** + * Reports whether a given encoding is available. + * @param name The encoding name. Typical values are "ASCII", "binary", or "UTF-8".For a complete list of supported encodings, see the JavaScript Tools Guide. + */ + isEncodingAvailable(name: string): boolean + + /** + * Opens a dialog so the user can select one or more files to open. + * Opens the built-in platform-specific file-browsing dialog in which a user can select an existing file or multiple files, and creates new File objects to represent the selected files. + * If the user clicks OK, returns a File object for the selected file, or an array of objects if multiple files are selected. + * If the user cancels, returns null. + * @param prompt The prompt text, displayed if the dialog allows a prompt. + * @param filter A filter that limits the types of files displayed in the dialog. In Windows,a filter expression such as "Javascript files:*.jsx;All files:*.*". In Mac OS, a filter function that takes a File instance and returns true if the file should be included in the display, false if it should not. + * @param multiSelect When true, the user can select multiple files and the return value is an array. + */ + openDialog(prompt?: string, filter?: any, multiSelect?: boolean): File + + /** + * Opens a dialog so the user can select a file name to save to. + * Opens the built-in platform-specific file-browsing dialog in which a user can select an existing file location to which to save information, and creates a new File object to represent the selected file location. + * If the user clicks OK, returns a File object for the selected file location. + * If the user cancels, returns null. + * @param prompt The prompt text, displayed if the dialog allows a prompt. + * @param filter In Windows only, a filter that limits the types of files displayed in the dialog. In Windows only,a filter expression such as "Javascript files:*.jsx;All files:*.*". Not used In Mac OS. + */ + saveDialog(prompt?: string, filter?: any): File + } + declare const File: FileConstructor + + /** + * Represents a file in the local file system in a platform-independent manner. + */ + interface File { + /** + * The full path name for the referenced file in URI notation. + */ + readonly absoluteURI: string + + /** + * If true, the object refers to a file system alias or shortcut. + */ + readonly alias: boolean + + /** + * The creation date of the referenced file, or null if the object does not refer to a file on disk. + */ + readonly created: Date + + /** + * In Mac OS, the file creator as a four-character string. In Windows or UNIX, value is "????". + */ + readonly creator: string + + /** + * The localized name of the referenced file, without the path specification. + */ + readonly displayName: string + + /** + * Gets or sets the encoding for subsequent read/write operations. + * One of the encoding constants listed in the JavaScript Tools Guide. If the value is not recognized, uses the system default encoding.A special encoder, BINARY, is used to read binary files. It stores each byte of the file as one Unicode character regardless of any encoding. When writing, the lower byte of each Unicode character is treated as a single byte to write. + */ + encoding: string + + /** + * When true, a read attempt caused the current position to be at the end of the file, or the file is not open. + */ + readonly eof: boolean + + /** + * A string containing a message describing the most recent file system error. + * Typically set by the file system, but a script can set it. Setting this value clears any error message and resets the error bit for opened files. Contains the empty string if there is no error. + */ + error: string + + /** + * If true, this object refers to a file or file-system alias that actually exists in the file system. + */ + readonly exists: boolean + + /** + * The platform-specific full path name for the referenced file. + */ + readonly fsName: string + + /** + * The full path name for the referenced file in URI notation. + */ + readonly fullName: string + + /** + * When true, the file is not shown in the platform-specific file browser. + * If the object references a file-system alias or shortcut, the flag is altered on the alias, not on the original file. + */ + hidden: boolean + + /** + * The size of the file in bytes. + * Can be set only for a file that is not open, in which case it truncates or pads the file with 0-bytes to the new length. + */ + length: number + + /** + * How line feed characters are written in the file system. + * One of the values "Windows", "Macintosh", or "Unix". + */ + lineFeed: string + + /** + * The date of the referenced file's last modification, or null if the object does not refer to a file on the disk. + */ + readonly modified: Date + + /** + * The file name portion of the absolute URI for the referenced file, without the path specification. + */ + readonly name: string + + /** + * The Folder object for the folder that contains this file. + */ + readonly parent: Folder + + /** + * The path portion of the absolute URI for the referenced file, without the file name. + */ + readonly path: string + + /** + * When true, prevents the file from being altered or deleted. + * If the referenced file is a file-system alias or shortcut, the flag is altered on the alias, not on the original file. + */ + readonly: boolean + + /** + * The path name for the object in URI notation, relative to the current folder. + */ + readonly relativeURI: string + + /** + * The file type as a four-character string. + * In Mac OS, the Mac OS file type. + * In Windows, "appl" for .EXE files, "shlb" for .DLL files and "TEXT" for any other file. + */ + readonly type: string + + /** + * Changes the path specification of the referenced file. + * @param path A string containing the new path, absolute or relative to the current folder. + */ + changePath(path: string): boolean + + /** + * Closes this open file. + * Returns true if the file was closed successfully, false if an I/O error occurred. + */ + close(): boolean + + /** + * Copies this object’s referenced file to the specified target location. + * Resolves any aliases to find the source file. If a file exists at the target location, it is overwritten. + * Returns true if the copy was successful. + * @param target A string with the URI path to the target location, or a File object that references the target location. + */ + copy(target: string): boolean + + /** + * Makes this file a file-system alias or shortcut to the specified file. + * The referenced file for this object must not yet exist on disk. Returns true if the operation was successful. + * @param path A string containing the path of the target file. + */ + createAlias(path: string): void + + /** + * Executes or opens this file using the appropriate application, as if it had been double-clicked in a file browser. + * You can use this method to run scripts, launch applications, and so on.Returns true immediately if the application launch was successful. + */ + execute(): boolean + + /** + * Retrieves and returns the path for this file, relative to the specified base path, in URI notation. + * If no base path is supplied, the URI is relative to the path of the current folder.Returns a string containing the relative URI. + * @param basePath A base path in URI notation. + */ + getRelativeURI(basePath: string): string + + /** + * Opens the referenced file for subsequent read/write operations. The method resolves any aliases to find the file. + * Returns true if the file was opened successfully.The method attempts to detect the encoding of the open file. It reads a few bytes at the current location and tries to detect the Byte Order Mark character 0xFFFE. If found, the current position is advanced behind the detected character and the encoding property is set to one of the strings UCS-2BE, UCS-2LE, UCS4-BE, UCS-4LE, or UTF-8. If the marker character is not found, it checks for zero bytes at the current location and makes an assumption about one of the above formats (except UTF-8). If everything fails, the encoding property is set to the system encoding. + * IMPORTANT: Be careful about opening a file more than once. The operating system usually permits you to do so, but if you start writing to the file using two different File objects, you can destroy your data. + * @param mode The read-write mode, a single-character string. One of these characters: r (read) Opens for reading. If the file does not exist or cannot be found, the call fails. w (write) Opens a file for writing. If the file exists, its contents are destroyed. If the file does not exist, creates a new, empty file. e (edit) Opens an existing file for reading and writing. a (append) Opens an existing file for reading and writing, and moves the current position to the end of the file. + * @param type In Mac OS, the type of a newly created file, a 4-character string. Ignored in Windows and UNIX. + * @param creator In Mac OS, the creator of a newly created file, a 4-character string. Ignored in Windows and UNIX. + */ + open(mode: string, type?: string, creator?: string): boolean + + /** + * Opens the built-in platform-specific file-browsing dialog, in which the user can select an existing file or files, and creates new File objects to represent the selected files. + * Differs from the class method openDialog() in that it presets the current folder to this File object’s parent folder and the current file to this object’s associated file. + * If the user clicks OK, returns a File or Folder object for the selected file or folder, or an array of objects. + * If the user cancels, returns null. + * @param prompt A string containing the prompt text, if the dialog allows a prompt. + * @param filter A filter that limits the types of files displayed in the dialog. In Windows,a filter expression such as "Javascript files:*.jsx;All files:*.*". In Mac OS, a filter function that takes a File instance and returns true if the file should be included in the display, false if it should not. + * @param multiSelect When true, the user can select multiple files and the return value is an array. + */ + openDlg(prompt?: string, filter?: any, multiSelect?: boolean): File + + /** + * Reads the contents of the file, starting at the current position. + * Returns a string that contains up to the specified number of characters. If a number of characters is not supplied, reads from the current position to the end of the file. If the file is encoded, multiple bytes might be read to create single Unicode characters. + * @param chars An integer specifying the number of characters to read. + */ + read(chars?: number): string + + /** + * Reads a single text character from the file at the current position. + * Line feeds are recognized as CR, LF, CRLF or LFCR pairs.If the file is encoded, multiple bytes might be read to create a single Unicode character. Returns a string that contains the character. + */ + readch(): string + + /** + * Reads a single line of text from the file at the current position. + * Line feeds are recognized as CR, LF, CRLF or LFCR pairs.. If the file is encoded, multiple bytes might be read to create single Unicode characters. Returns a string that contains the text. + */ + readln(): string + + /** + * Deletes the file associated with this object from disk immediately, without moving it to the system trash. + * Does not resolve aliases; instead, deletes the referenced alias or shortcut file itself. Returns true if the file was successfully removed. + * IMPORTANT: Cannot be undone. It is recommended that you prompt the user for permission before deleting. + */ + remove(): boolean + + /** + * Renames the associated file. + * Does not resolve aliases, but renames the referenced alias or shortcut file itself. Returns true if the file was successfully renamed. + * @param newName The new file name, with no path information. + */ + rename(newName: string): boolean + + /** + * Attempts to resolve the file-system alias or shortcut that this object refers to. + * If successful, creates and returns a new File object that points to the resolved file system element. Returns null if this object does not refer to an alias, or if the alias could not be resolved. + */ + resolve(): File + + /** + * Opens the built-in platform-specific file-browsing dialog, in which the user can select an existing file location to which to save information, and creates a new File object to represent the selected file. + * Differs from the class method saveDialog() in that it presets the current folder to this File object’s parent folder and the file to this object’s associated file. + * If the user clicks OK, returns a File object for the selected file. + * If the user cancels, returns null. + * @param prompt A string containing the prompt text, if the dialog allows a prompt. + * @param filter In Windows only, a filter that limits the types of files displayed in the dialog. In Windows only,a filter expression such as "Javascript files:*.jsx;All files:*.*". Not used In Mac OS. + */ + saveDlg(prompt?: string, filter?: any): File + + /** + * Seeks to a given position in the file. + * The new position cannot be less than 0 or greater than the current file size. Returns true if the position was changed. + * @param pos The new current position in the file as an offset in bytes from the start, current position, or end, depending on the mode. + * @param mode The seek mode. One of: 0: Seek to absolute position, where pos=0 is the first byte of the file. This is the default. 1: Seek relative to the current position. 2. Seek backward from the end of the file. + */ + seek(pos: number, mode?: number): boolean + + /** + * Retrieves the current position as a byte offset from the start of the file. + * Returns a number, the position index. + */ + tell(): number + + /** + * Creates and returns a serialized string representation of this object. + * Pass the resulting string to eval() to recreate the object. + */ + toSource(): string + + /** + * Converts this object to a string. + */ + toString(): string + + /** + * Writes the specified text to the file at the current position. + * You can supply multiple text values; the strings are concatenated to form a single string.For encoded files, writing a single Unicode character may write multiple bytes. Returns true if the write was successful.IMPORTANT: Be careful not to write to a file that is open in another application or object, as this can overwrite existing data. + * @param text A text string to be written. + */ + write(text: string): boolean + + /** + * Writes a string to the file at the current position and appends a line-feed sequence. + * You can supply multiple text values. The strings are concatenated into a single string, which is written in the file followed by one line-feed sequence, of the style specified by this object's linefeed property.For encoded files, writing a single Unicode character may write multiple bytes.Returns true if the write was successful.IMPORTANT: Be careful not to write to a file that is open in another application or object, as this can overwrite existing data. + * @param text A text string to be written. + */ + writeln(text: string): boolean + } + + interface FolderConstructor { + readonly prototype: Folder + + /** + * Creates and returns a new Folder object referring to a given file-system location. + * If the path name refers to an already existing disk file, a File object is returned instead.Returns the new Folder object. + * @param path The absolute or relative path to the folder associated with this object, specified in URI format. The value stored in the object is the absolute path.The path need not refer to an existing folder. If the path refers to an existing file, rather than a folder: The Folder() function returns a File object instead of a Folder object. The new operator returns a Folder object for a nonexisting folder with the same name. + */ + new (path?: string): Folder + (path?: string): Folder + + /** + * The folder containing the application data for all users. + * In Windows, the value of %APPDATA% (by default, C:\\Documents and Settings\\All Users\\Application Data) + * In Mac OS, /Library/Application Support + */ + readonly appData: Folder + + /** + * In Mac OS, a Folder object for the folder containing the bundle of the running application. + */ + readonly appPackage: Folder + + /** + * A Folder object for the folder containing common files for all programs installed by the user. + * In Windows, the value of %CommonProgramFiles% (by default, C:\\Program Files\\Common Files) + * In Mac OS, /Library/Application Support + */ + readonly commonFiles: Folder + + /** + * A Folder object for the current folder. + * Assign a Folder object or a string containing the new path name to set the current folder. This is a class property accessed through the Folder constructor. + */ + current: Folder + + /** + * A Folder object for the folder that contains the user’s desktop. + * In Windows, C:\\Documents and Settings\\username\\Desktop + * In Mac OS, ~/Desktop + */ + readonly desktop: Folder + + /** + * The name of the current file system. + * One of "Windows", "Macintosh", or "Unix". + */ + readonly fs: string + + /** + * A folder pointing to the user's My Documents folder. + * In Windows, C:\\Documents and Settings\\username\\My Documents + * In Mac OS,~/Documents + */ + readonly myDocuments: Folder + + /** + * A Folder object for the folder containing the executable image of the running application. + */ + readonly startup: Folder + + /** + * A Folder object for the folder containing the operating system files. + * In Windows, the value of %windir% (by default, C:\\Windows) + * In Mac OS, /System + */ + readonly system: Folder + + /** + * A Folder object for the default folder for temporary files. + */ + readonly temp: Folder + + /** + * A Folder object for the folder containing deleted items. On Windows, the trash folder is a virtual + * folder containing a database; therefore, the property value is null on Windows. + */ + readonly trash: Folder + + /** + * A Folder object for the folder containing the user's application data. + * In Windows, the value of %USERDATA% (by default, C:\\Documents and Settings\\username\\Application Data) + * In Mac OS,~/Library/Application Support. + */ + readonly userData: Folder + + /** + * Decodes a UTF-8 encoded string as required by RFC 2396, and returns the decoded string. + * See also String.decodeURI(). + * @param uri The UTF-8 string to decode. + */ + decode(uri: string): string + + /** + * Encodes a string as required by RFC 2396, and returns the encoded string. + * All special characters are encoded in UTF-8 and stored as escaped characters starting with the percent sign followed by two hexadecimal digits. For example, the string "my file" is encoded as "my%20file". + * Special characters are those with a numeric value greater than 127, except the following: / - _ . ! ~ * ' ( ) + * See also encodeURI(). + * @param name The string to encode. + */ + encode(name: string): string + + /** + * Reports whether a given encoding is available. + * @param name The encoding name. Typical values are "ASCII", "binary", or "UTF-8".For a complete list of supported encodings, see the JavaScript Tools Guide. + */ + isEncodingAvailable(name: string): boolean + + /** + * Opens the built-in platform-specific file-browsing dialog, and creates a new File or Folder object for the selected file or folder. + * Differs from the object method selectDlg() in that it does not preselect a folder. + * If the user clicks OK, returns a File or Folder object for the selected file or folder. + * If the user cancels, returns null. + * @param prompt The prompt text, if the dialog allows a prompt. + */ + selectDialog(prompt?: string): Folder + } + declare const Folder: FolderConstructor + + /** + * Represents a file-system folder or directory in a platform-independent manner. + */ + interface Folder { + /** + * The full path name for the referenced folder in URI notation. + */ + readonly absoluteURI: string + + /** + * When true, the object refers to a file system alias or shortcut. + */ + readonly alias: boolean + + /** + * The creation date of the referenced folder, or null if the object does not refer to a folder on disk. + */ + readonly created: Date + + /** + * The localized name portion of the absolute URI for the referenced folder, without the path specification. + */ + readonly displayName: string + + /** + * A message describing the most recent file system error. + * Typically set by the file system, but a script can set it. Setting this value clears any error message and resets the error bit for opened files. Contains the empty string if there is no error. + */ + error: string + + /** + * When true, this object refers to a folder that currently exists in the file system. + */ + readonly exists: boolean + + /** + * The platform-specific name of the referenced folder as a full path name. + */ + readonly fsName: string + + /** + * The full path name for the referenced folder in URI notation. . + */ + readonly fullName: string + + /** + * The date of the referenced folder's last modification, or null if the object does not refer to a folder on disk. + */ + readonly modified: Date + + /** + * The folder name portion of the absolute URI for the referenced file, without the path specification. + */ + readonly name: string + + /** + * TThe Folder object for the folder that contains this folder, or null if this object refers to the root folder of a volume. + */ + readonly parent: Folder + + /** + * The path portion of the object absolute URI for the referenced file, without the folder name. + */ + readonly path: string + + /** + * The path name for the referenced folder in URI notation, relative to the current folder. + */ + readonly relativeURI: string + + /** + * Changes the path specification of the referenced folder. + * @param path A string containing the new path, absolute or relative to the current folder. + */ + changePath(path: string): boolean + + /** + * Creates a folder at the location given by this object's path property. + * Returns true if the folder was created. + */ + create(): boolean + + /** + * Opens this folder in the platform-specific file browser (as if it had been double-clicked in the file browser). + * Returns true immediately if the folder was opened successfully. + */ + execute(): boolean + + /** + * Retrieves the contents of this folder, filtered by the supplied mask. + * Returns an array of File and Folder objects, or null if this object's referenced folder does not exist. + * @param mask A search mask for file names, specified as a string or a function. A mask string can contain question mark (?) and asterisk (*) wild cards. Default is "*", which matches all file names. Can also be the name of a function that takes a File or Folder object as its argument. It is called for each file or folder found in the search; if it returns true, the object is added to the return array. NOTE: In Windows, all aliases end with the extension .lnk. ExtendScript strips this from the file name when found, in order to preserve compatibility with other operating systems. You can search for all aliases by supplying the search mask "*.lnk", but note that such code is not portable. + */ + getFiles(mask: any): Array + + /** + * Retrieves and returns the path for this file, relative to the specified base path, in URI notation. + * If no base path is supplied, the URI is relative to the path of the current folder.Returns a string containing the relative URI. + * @param basePath A base path in URI notation. + */ + getRelativeURI(basePath?: string): string + + /** + * Deletes the folder associated with this object from disk immediately, without moving it to the system trash. + * Folders must be empty before they can be deleted. Does not resolve aliases; instead, deletes the referenced alias or shortcut file itself. Returns true if the file was successfully removed. + * IMPORTANT: Cannot be undone. It is recommended that you prompt the user for permission before deleting. + */ + remove(): boolean + + /** + * Renames the associated folder. + * Does not resolve aliases, but renames the referenced alias or shortcut file itself. Returns true if the folder was successfully renamed. + * @param newName The new folder name, with no path information. + */ + rename(newName: string): boolean + + /** + * Attempts to resolve the file-system alias or shortcut that this object refers to. + * If successful, creates and returns a new Folder object that points to the resolved file system element. Returns null if this object does not refer to an alias, or if the alias could not be resolved. + */ + resolve(): Folder + + /** + * Opens the built-in platform-specific file-browsing dialog, and creates a new File or Folder object for the selected file or folder. + * Differs from the class method selectDialog() in that it preselects this folder. + * If the user clicks OK, returns a File or Folder object for the selected file or folder. + * If the user cancels, returns null. + * @param prompt The prompt text, if the dialog allows a prompt. + */ + selectDlg(prompt?: string): Folder + + /** + * Creates and returns a serialized string representation of this object. + * Pass the resulting string to eval() to recreate the object. + */ + toSource(): string + + /** + * Converts this object to a string. + */ + toString(): string + } + + interface SocketConstructor { + readonly prototype: Socket + + /** + * Creates a new Socket object. + */ + new (): Socket + (): Socket + } + declare const Socket: SocketConstructor + + /** + * Creates a TCP/IP connection, or establishes a TCP/IP server. + */ + interface Socket { + /** + * When true, the connection is active. + */ + readonly connected: boolean + + /** + * Sets or retrieves the name of the encoding used to transmit data. + * Typical values are "ASCII", "BINARY", or "UTF-8". + */ + encoding: string + + /** + * When true, the receive buffer is empty. + */ + readonly eof: boolean + + /** + * A message describing the most recent error. Setting this value clears any error message. + */ + error: string + + /** + * The name of the remote computer when a connection is established. + * If the connection is shut down or does not exist, the property contains the empty string. + */ + readonly host: string + + /** + * The timeout in seconds to be applied to read or write operations. + */ + timeout: number + + /** + * Terminates the open connection. + * Returns true if the connection was closed, false on I/O errors. + * Deleting the object also closes the connection, but not until JavaScript garbage-collects the object. The connection might stay open longer than you wish if you do not close it explicitly. + */ + close(): boolean + + /** + * Instructs the object to start listening for an incoming connection. + * The call to open() and the call to listen()are mutually exclusive. Call one function or the other, not both. + * @param port The TCP/IP port number to listen on. Valid port numbers are 1 to 65535. Typical values are 80 for a Web server, 23 for a Telnet server and so on. + * @param encoding The encoding to be used for the connection Typical values are "ASCII", "BINARY", or "UTF-8". + */ + listen(port: number, encoding?: string): boolean + + /** + * Opens the connection for subsequent read/write operations. + * The call to open() and the call to listen() are mutually exclusive. Call one function or the other, not both. + * @param host The server to connect to. This can be a DNS name, an IPv4 address, or an IPv6 address, followed by a colon and a port number. + * @param encoding The encoding to be used for the connection Typical values are "ASCII", "binary", or "UTF-8". + */ + open(host: string, encoding?: string): boolean + + /** + * Checks a listening object for a new incoming connection. + * If a connection request was detected, the method returns a new Socket object that wraps the new connection. Use this connection object to communicate with the remote computer. After use, close the connection and delete the JavaScript object. If no new connection request was detected, the method returns null. + */ + poll(): Socket + + /** + * Reads up to the specified number of characters from the connection. CR characters are ignored unless the encoding is set to "BINARY". + * Returns a string that contains up to the number of characters that were supposed to be read, or the number of characters read before the connection closed or timed out. + * @param count The number of characters to read. If not supplied, the connection attempts to read as many characters it can get and returns immediately. + */ + read(count?: number): string + + /** + * Reads one line of text up to the next line feed. + * Line feeds are recognized as LF or CRLF pairs. CR characters are ignored. Returns a string containing the characters. + */ + readln(): string + + /** + * Concatenates all arguments into a single string and writes that string to the connection. + * @param text Any number of string values. All arguments are concatenated to form the string to be written. CRLF sequences are converted to LFs unless the encoding is set to "BINARY". + */ + write(text: string): boolean + + /** + * Concatenates all arguments into a single string, appends a LF character, and writes that string to the connection. + * @param text Any number of string values. All arguments are concatenated to form the string to be written. CRLF sequences are converted to LFs unless the encoding is set to "BINARY". + */ + writeln(text: string): boolean + } + + /** + * Provides information about a method, a property or a method parameters. + */ + interface ReflectionInfo { + /** + * The description of method or function arguments. + */ + readonly arguments: ReflectionInfo[] + + /** + * The data type. + */ + readonly dataType: string + + /** + * The default value. + */ + readonly defaultValue: any + + /** + * The long description text. + */ + readonly description: string + + /** + * The short description text. + */ + readonly help: string + + /** + * Contains true if the class describes a collection class. + */ + readonly isCollection: boolean + + /** + * The maximum value. + */ + readonly max: number + + /** + * The minimum value. + */ + readonly min: number + + /** + * The element name. + */ + readonly name: string + + /** + * The class object that this element belongs to. + */ + readonly parent: Reflection + + /** + * Sample code, if present. + */ + readonly sampleCode: string + + /** + * A file containing sample code. May be null. + */ + readonly sampleFile: File + + /** + * The element type. + * One of unknown, readonly, readwrite, createonly, method or parameter. + */ + readonly type: string + } + declare const ReflectionInfo: ReflectionInfo + + /** + * Provides information about a class. + */ + interface Reflection { + /** + * The long description text. + */ + readonly description: string + + /** + * The short description text. + */ + readonly help: string + + /** + * An array of method descriptions. + */ + readonly methods: ReflectionInfo[] + + /** + * The class name. + */ + readonly name: string + + /** + * An array of property descriptions. + */ + readonly properties: ReflectionInfo[] + + /** + * Sample code, if present. + */ + readonly sampleCode: string + + /** + * A file containing sample code. May be null. + */ + readonly sampleFile: File + + /** + * An array of class method descriptions. + */ + readonly staticMethods: ReflectionInfo[] + + /** + * An array of class property descriptions. + */ + readonly staticProperties: ReflectionInfo[] + + /** + * Finds an element description by name. + * @param name The name of the element to find. + */ + find(name: string): ReflectionInfo + + /** + * Returns this class information as XML in OMV format. + */ + toXML(): XML + } + declare const Reflection: Reflection + + interface QNameConstructor { + readonly prototype: QName + + /** + * Creates a QName object. + * @param uri The URI, specified as a Namespace object, an existing QName object, or string. If this is a Namespace object, the URI is set to the namespace URI, and there is no local name. If this is a QName object, the URI and localName is set to those of that object. If this is a string, the URI is set to that string. + * @param name The local name. Used only if URI is given as a string. + */ + new (uri: any, name?: string): QName + (uri: any, name?: string): QName + } + declare const QName: QNameConstructor + + /** + * A qualified XML name, containing the URI and the local name. + */ + interface QName { + /** + * The local name part of the qualified name. + */ + readonly localName: string + + /** + * The URI part of the qualified name. + */ + readonly uri: string + } + + interface NamespaceConstructor { + readonly prototype: Namespace + + /** + * Creates a Namespace object. + * @param prefix The URIprefix, specified as an existing Namespace object, QName object, or string. If this is a Namespace or a QName object, the URI and prefix are set to that of the object. If this is a string, the prefix is set to that string, and the URI must be specified. + * @param uri The URI if the prefix is specified as a string. + */ + new (prefix: any, uri?: string): Namespace + (prefix: any, uri?: string): Namespace + } + declare const Namespace: NamespaceConstructor + + /** + * A XML namespace object. + */ + interface Namespace { + /** + * The named prefix. + */ + readonly prefix: string + + /** + * The URI. + */ + readonly uri: string + } + + interface XMLConstructor { + readonly prototype: XML + + /** + * Parses an XML string. Throws an error if the XML is incorrect. + * @param text The text to parse. + */ + new (text: string): XML + (text: string): XML + + /** + * Controls whether XML comments should be parsed (false) or ignored (true). + */ + ignoreComments: boolean + + /** + * Controls whether XML preprocessing instructions should be parsed (false) or ignored (true). + */ + ignoreProcessingInstructions: boolean + + /** + * Controls whether whitespace should be parsed (false) or ignored (true). + */ + ignoreWhitespace: boolean + + /** + * The number of spaces used to indent pretty-printed XML. + */ + prettyIndent: number + + /** + * When true, XML is pretty-printed when converting to a string. + */ + prettyPrinting: boolean + + /** + * Returns an object containing the default parsing and print settings for XML. + */ + defaultSettings(): object + + /** + * Sets the parsing and print setting for XML using an object returned by the settings() method. + * @param obj The object containing the settings to set. + */ + setSettings(obj: object): void + + /** + * Returns an object containing the current parsing and print settings for XML. + */ + settings(): object + } + declare const XML: XMLConstructor + + /** + * Wraps XML into an object. + */ + interface XML { + /** + * Adds a namespace declaration to the node. Returns the XML object itself. + * @param namespace The namespace to add. + */ + addNamespace(namespace: Namespace): XML + + /** + * Appends the given XML to this XML as a child. Returns the XML object itself. + * If the argument is not XML, creates a new XML element containing the argument as text. The element name of that new XML is the same as the last element in the original XML. + * @param child The child XML to add. + */ + appendChild(child: XML): XML + + /** + * Returns a list containing all attribute elements matching the given name. + * @param name The attribute name to look for. + */ + attribute(name: string): XML + + /** + * Returns a list containing all attribute elements. + */ + attributes(): XML + + /** + * Returns a list containing all children of this XML matching the given element name. + * If the argument is a number, uses the number as index into the array of children. + * @param name The name or the index of the child element. + */ + child(name: string): XML + + /** + * Returns a number representing the ordinal position of this XML object within the context of its parent. + */ + childIndex(): number + + /** + * Returns an XML object containing all the properties of this XML object in order. + */ + children(): XML + + /** + * Returns an XML object containing the properties of this XML object that represent XML comments. + */ + comments(): XML + + /** + * Checks if this XML object contains the given XML object. + * @param xml The XML to search for. + */ + contains(xml: XML): boolean + + /** + * Creates a copy of this XML object. + */ + copy(): XML + + /** + * Returns all the XML-valued descendants of this XML object with the given name. + * If the name parameter is omitted, returns all descendants of this XML object. + * @param name The name of the descendant to find. + */ + descendants(name?: string): XML + + /** + * Returns a list of XML children that are elements with a given name, or all children that are XML elements. + * @param name The element name. If not supplied, gets all children that are XML elements. + */ + elements(name?: string): XML + + /** + * Reports whether this XML object contains complex content. + * An XML object is considered to contain complex content if it represents an XML element that has child elements. XML objects representing attributes, comments, processing instructions and text nodes do not have complex content. The existence of attributes, comments, processing instructions and text nodes within an XML object is not significant in determining if it has complex content. + */ + hasComplexContent(): boolean + + /** + * Reports whether this XML object contains simple content. + * An XML object is considered to contain simple content if it represents a text node, represents an attribute node or if it represents an XML element that has no child elements. XML objects representing comments and processing instructions do not have simple content. The existence of attributes, comments, processing instructions and text nodes within an XML object is not significant in determining if it has simple content. + */ + hasSimpleContent(): boolean + + /** + * Returns an array of Namespace objects mirroring the current list of valid namespaces at this element. + * The last element of thereturned array is the default namespace. + */ + inScopeNamespaces(): Namespace[] + + /** + * Inserts the given child2 after the given child1 in this XML object and returns this XML object. + * If child1 is null, the method inserts child2 before all children of this XML object (that is, after none of them). If child1 does not exist in this XML object, the method returns without modifying this XML object. + * @param child1 The child to insert the other child after. If null, the method inserts child2 before all children of this XML object. + * @param child2 The XML to insert. + */ + insertChildAfter(child1: XML, child2: XML): void + + /** + * Inserts the given child2 before the given child1 in this XML object and returns this XML object. + * If child1 is null, the method inserts child2 after all children of this XML object (that is, before none of them). If child1 does not exist in this XML object, the method returns without modifying this XML object. + * @param child1 The child to search for. If null, the method inserts child2 after all children of this XML object. + * @param child2 The XML to insert. + */ + insertChildBefore(child1: XML, child2: XML): void + + /** + * Returns the number of elements contained in an XML list. If this XML object is not a list, returns 1. + */ + length(): number + + /** + * Returns the local name of this XML object. + * This value corresponds to the element name unless the name has a namespace prefix. For example, if the element has the name "ns:tag", the return value is "tag". + */ + localName(): string + + /** + * Returns a QName object containing the URI and the local name of the element. + */ + name(): QName + + /** + * Returns a Namespace object containing the namespace URI of the current element. + */ + namespace(): Namespace + + /** + * Returns an array containing all namespace declarations of this XML object. + */ + namespaceDeclarations(): Namespace[] + + /** + * Returns the type of this XML object as one of the strings "element", "attribute", "comment", "processing-instruction", or "text". + */ + nodeKind(): string + + /** + * Puts all text nodes in this and all descendant XML objects into a normal form by merging adjacent text nodes and eliminating empty text nodes. Returns this XML object. + */ + normalize(): XML + + /** + * Returns the parent object of this XML object. + * The root object, as returned by the XML constructor, does not have a parent and returns null. Note that the E4X standard does not define what happens if this XML object is a list containing elements with multiple parents. + */ + parent(): XML + + /** + * Inserts a given child into this object before its existing XML properties, and returns this XML object. + * @param child The XML to insert. + */ + prependChild(child: XML): XML + + /** + * Returns a list of preprocessing instructions. + * Collects processing-instructions with the given name, if supplied. Otherwise, returns an XML list containing all the children of this XML object that are processing-instructions regardless of their name. + * @param name The name of the preprocessing instruction to return. + */ + processingInstructions(name?: string): XML + + /** + * Removes the given namespace from this XML, and returns this XML. + * @param namespace The namespace to remove. + */ + removeNamespace(namespace: Namespace): XML + + /** + * Replaces the value of specified XML properties of this XML object returns this XML object. + * This method acts like the assignment operator. + * @param name The property name. Can be a numeric property name, a name for a set of XML elements, or the properties wildcard “*”. If this XML object contains no properties that match the name, the method returns without modifying this XML object. + * @param value The XML with which to replace the value of the matching property. Can be an XML object, XML list or any value that can be converted to a String with toString(). + */ + replace(name: string, value: XML): XML + + /** + * Replaces all of the XML-valued properties in this object with a new value, and returns this XML object. + * @param value The new value, which can be a single XML object or an XML list. + */ + setChildren(value: XML): XML + + /** + * Replaces the local name of this XML objectwith a string constructed from the given name + * The local name is any part behind a colon character. If there is no colon, it is the entire name. + * @param name The name to set. + */ + setLocalName(name: string): void + + /** + * Replaces the name of this XML object with the given QName object. + * @param name The fully qualified name. + */ + setName(name: QName): void + + /** + * Sets the namespace for this XML element. + * If the namespace has not been declared in the tree above this element, adds a namespace declaration. + * @param namespace The namespace to set. + */ + setNamespace(namespace: Namespace): void + + /** + * Returns an XML list containing all XML properties of this XML object that represent XML text nodes. + */ + text(): XML + + /** + * Returns the string representation of this object. + * For text and attribute nodes, this is the textual value of the node; for other elements, this is the result of calling the toXMLString() method. If this XML object is a list, concatenates the result of calling toString() on each element. + */ + toString(): string + + /** + * Returns an XML-encoded string representation of this XML object. + * Always includes the start tag, attributes and end tag of the XML object regardless of its content. It is provided for cases when the default XML to string conversion rules are not desired. Interprets the global settings XML.prettyPrint and XML.prettyIndent. + */ + toXMLString(): string + + /** + * Evaluates the given XPath expression in accordance with the W3C XPath recommendation, using this XML object as the context node. + * @param expr The XPath expression to use. + */ + xpath(expr: string): XML + } + + /** + * An XML list object. + * In this implementation, an XMLList object is synonymous to the XML object. The constructor accepts an XML list, but everything else works like theXML object. + */ + interface XMLList {} + declare const XMLList: XMLList + + interface UnitValueConstructor { + readonly prototype: UnitValue + + /** + * Creates a new UnitValue object. + */ + new (value: string | UnitValue): UnitValue + (value: string | UnitValue): UnitValue + + /** + * The base unit for all conversions. + */ + baseUnit: UnitValue + } + declare const UnitValue: UnitValueConstructor + + /** + * Represents a measurement as a combination of values and unit. + * Note that this object is not available in all applications. + */ + interface UnitValue { + /** + * The base unit. + */ + baseUnit: UnitValue + + /** + * The unit name. + */ + readonly type: string + + /** + * The numeric value. + */ + value: number + + /** + * Returns this instance as a different unit. + * @param unitName The unit name. + */ + as(unitName: string): UnitValue + + /** + * Converts this instance to a different unit. + * @param unitName The unit name. + */ + convert(unitName: string): any + } + + /** + * Only for TypeScript compatibility + */ + interface CallableFunction extends Function { + + } + + interface NewableFunction extends Function { + + } + + interface IArguments { + [index: number]: any + length: number + callee: Function + } + + /** + * Make all properties in T optional + */ + type Partial = { [P in keyof T]?: T[P] } + + /** + * Make all properties in T readonly + */ + type Readonly = { readonly [P in keyof T]: T[P] } + + /** + * From T pick a set of properties K + */ + type Pick = { [P in K]: T[P] } + + /** + * Construct a type with a set of properties K of type T + */ + type Record = { [P in K]: T } \ No newline at end of file diff --git a/pype/premiere/extensions/com.pype/jsx/global.d.ts b/pype/premiere/extensions/com.pype/jsx/global.d.ts new file mode 100644 index 00000000000..2e20ea07b3f --- /dev/null +++ b/pype/premiere/extensions/com.pype/jsx/global.d.ts @@ -0,0 +1,149 @@ +/** + * The global BridgeTalk object. + */ +declare var BridgeTalk: any + +/** + * The Infinity global property is a predefined variable with the value for infinity. + */ +declare var Infinity: number + +/** + * The NaN global property is a predefined variable with the value NaN (Not-a-Number), as specified by the IEEE-754 standard. + */ +declare var NaN: number + +/** + * The application object + */ +declare var app: Application +declare interface Application {} + +/** + * Displays an alert box + * @param message The text to display + * @param title The title of the alert; ignored on the Macintosh + * @param errorIcon Display an Error icon; ignored on the Macintosh + */ +declare function alert(message: string, title?: string, errorIcon?: boolean): void + +/** + * Displays an alert box with Yes and No buttons; returns true for Yes + * @param message The text to display + * @param noAsDefault Set to true to set the No button as the default button + * @param title The title of the alert; ignored on the Macintosh + */ +declare function confirm(message: string, noAsDefault?: boolean, title?: string): boolean + +/** + * Decodes a string created with encodeURI(). + * @param uri The text to decode. + */ +declare function decodeURI(uri: string): string + +/** + * Decodes a string created with encodeURIComponent(). + * @param uri The text to decode. + */ +declare function decodeURIComponent(uri: string): string + +/** + * Encodes a string after RFC2396. + * Create an UTF-8 ASCII encoded version of this string. The string is converted into UTF-8. Every non-alphanumeric character is encoded as a percent escape + * character of the form %xx, where xx is the hex value of the character. After the conversion to UTF-8 encoding and escaping, it is guaranteed that the string does not contain characters codes greater than 127. The list of characters not to be encoded is -_.!~*'();/?:@&=+$,#. The method returns false on errors. + * @param text The text to encode. + */ +declare function encodeURI(text: string): string + +/** + * Encodes a string after RFC2396. + * Create an UTF-8 ASCII encoded version of this string. The string is converted into UTF-8. Every non-alphanumeric character is encoded as a percent escape + * character of the form %xx, where xx is the hex value of the character. After the conversion to UTF-8 encoding and escaping, it is guaranteed that the string does not contain characters codes greater than 127. The list of characters not to be encoded is -_.!~*'(). The method returns false on errors. + * @param text The text to encode. + */ +declare function encodeURIComponent(text: string): string + +/** + * Creates a URL-encoded string from aString. + * In the new string, characters of aString that require URL encoding are replaced with the format %xx, where xx is the hexadecimal value of the character code in the Unicode character set.This format is used to transmit information appended to a URL during, for example, execution of the GET method.Use the unescape() global function to translate the string back into its original format. Returns a string which is aString URL-encoded. + * @param aString The string to be encoded. + */ +declare function escape(aString: string): string + +/** + * Evaluates its argument as a JavaScript script, and returns the result of evaluation. + * You can pass the result of an object's toSource() method to reconstruct that object. + * @param stringExpression The string to evaluate. + */ +declare function eval(stringExpression: string): any + +/** + * Evaluates an expression and reports whether the result is a finite number. + * Returns true if the expression is a finite number, false otherwise. False if the value is infinity or negative infinity. + * @param expression Any valid JavaScript expression. + */ +declare function isFinite(expression: number): boolean + +/** + * Evaluates an expression and reports whether the result is "Not-a-Number" (NaN). + * Returns true if the result of evaluation is not a number (NaN), false if the value is a number. + * @param expression Any valid JavaScript expression. + */ +declare function isNaN(expression: number): boolean + +/** + * Returns true if the supplied string is a valid XML name. + * @param name The XML name to test. + */ +declare function isXMLName(name: string): boolean + +/** + * Localizes a ZString-encoded string and merges additional arguments into the string. + * @param what The string to localize. A ZString-encoded string that can contain placeholder for additional arguments in the form %1 to %n. + * @param arguments Optional argument(s) to be merged into the string. There may be more than one argument. + */ +declare function localize(what: string, ...arguments: any[]): string + +/** + * Extracts a floating-point number from a string. + * Parses a string to find the first set of characters that can be converted to a floating point number, and returns that number, or NaN if it does not encounter characters that it can converted to a number.The function supports exponential notation. + * @param text The string from which to extract a floating point number. + */ +declare function parseFloat(text: string): number + +/** + * Extracts an integer from a string. + * Parses a string to find the first set of characters, in a specified base, that can be converted to an integer, and returns that integer, or NaN if it does not encounter characters that it can convert to a number. + * @param text The string from which to extract an integer. + * @param base The base of the string to parse (from base 2 to base 36). If not supplied, base is determined by the format of string. + */ +declare function parseInt(text: string, base?: number): number + +/** + * Displays a dialog allowing the user to enter text + * Returns null if the user cancelled the dialog, the text otherwise + * @param prompt The text to display + * @param default_ The default text to preset the edit field with + * @param title The title of the dialog; + */ +declare function prompt(prompt: string, default_?: string, title?: string): string + +/** + * Defines the default XML namespace. + * This is a replacement function for the standard JavaScript statement set default xml namespace. + * @param namespace The namespace to use. Omit this parameter to return to the empty namespace. This is either a Namespace object or a string. + */ +declare function setDefaultXMLNamespace(namespace: Namespace): void + +/** + * Translates URL-encoded string into a regular string, and returns that string. + * Use the escape() global function to URL-encode strings. + * @param stringExpression The URL-encoded string to convert. + */ +declare function unescape(stringExpression: string): string + +/** + * Creates a source code representation of the supplied argument, and returns it as a string. + * @param what The object to uneval. + */ +declare function uneval(what: any): string \ No newline at end of file diff --git a/pype/premiere/extensions/com.pype/jsx/jsconfig.json b/pype/premiere/extensions/com.pype/jsx/jsconfig.json new file mode 100644 index 00000000000..f97a86db74d --- /dev/null +++ b/pype/premiere/extensions/com.pype/jsx/jsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "noLib" : true, + "checkJs": true + }, + "include": [ + "**/*" + ] +} \ No newline at end of file diff --git a/pype/premiere/extensions/com.pype/jsx/pype.jsx b/pype/premiere/extensions/com.pype/jsx/pype.jsx new file mode 100644 index 00000000000..684cef5e5a2 --- /dev/null +++ b/pype/premiere/extensions/com.pype/jsx/pype.jsx @@ -0,0 +1,1074 @@ +/* global app, qe, alert, File, $, JSON, ProjectItemType, CSXSEvent, XMPMeta, parseFloat */ +/* + .____ _ ___ .____.______ +--- - - -- / . \// // . \ ___/ --- ---- - - + - --- --- / ____/ __// ____/ /_/ --- - -- --- + /__/ /___/ /__/ /______/ + ._- -=[ PyPe 4 3veR ]=- -_. +*/ + +if (ExternalObject.AdobeXMPScript === undefined) { + ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript'); +} + +// this is needed for CSXSEvent to work +if (ExternalObject.PlugPlugExternalObject === undefined) { + ExternalObject.PlugPlugExternalObject = new ExternalObject( "lib:PlugPlugExternalObject"); +} +// variable pype is defined in pypeAvalon.jsx +$.pype = { + presets: null, + + expectedJobs: [], + + setEnvs: function (env) { + for (var key in env) { + $.setenv(key, env[key]); + } + }, + + importClips: function (obj) { + app.project.importFiles(obj.paths); + return JSON.stringify(obj); + }, + + convertPathString: function (path) { + return path.replace(new RegExp('\\\\', 'g'), '/').replace(new RegExp('//\\?/', 'g'), '').replace(new RegExp('/', 'g'), '\\').replace('UNC', '\\'); + }, + + getProjectFileData: function () { + app.enableQE(); + var projPath = new File(app.project.path); + var obj = { + projectfile: app.project.name, + projectpath: $.pype.convertPathString(projPath.fsName), + projectdir: $.pype.convertPathString(app.project.path).split('\\').slice(0, -1).join('\\') + }; + return JSON.stringify(obj); + }, + + getSequences: function () { + var project = app.project; + var sequences = []; + for (var i = 0; i < project.sequences.numSequences; i++) { + var seq = project.sequences[i]; + seq.clipNames = []; + sequences[i] = seq; + $.pype.log('sequences[i] id: ' + project.sequences[i].sequenceID); + } + + var obj = { + sequences: sequences + }; + return JSON.stringify(obj); + }, + + getSequenceItems: function (seqs) { + var sequences = seqs; + // $.pype.log('getSequenceItems sequences obj from app: ' + sequences); + + var rootFolder = app.project.rootItem; + var binCounter = -1; + var rootSeqCounter = -1; // count sequences in root folder + + // walk through root folder of project to differentiate between bins, sequences and clips + for (var i = 0; i < rootFolder.children.numItems; i++) { + // $.pype.log('\nroot item at ' + i + " is " + rootFolder.children[i].name + " of type " + rootFolder.children[i].type); + var item = rootFolder.children[i]; + // $.pype.log('item has video tracks? ' + item.videoTracks); + if (item.type === 2) { // bin + binCounter++; + walkBins(item, 'root', binCounter); + } else if (item.type === 1 && !item.getMediaPath()) { // sequence OR other type of object + // $.pype.log('\nObject of type 1 in root: ' + typeof item + ' ' + item.name); + if (objectIsSequence(item)) { // objects of type can also be other objects such as titles, so check if it really is a sequence + // $.pype.log('\nSequence in root: ' + item.name ); + rootSeqCounter++; + var seq = app.project.sequences[rootSeqCounter]; + // $.pype.log('\nSequence in root, guid: ' + seq ); + for (var property in seq) { + if (Object.prototype.hasOwnProperty.call(seq, property)) { + $.pype.log('\nSequence in root: ' + seq); + $.pype.log('qe sequence prop: ' + property); + } + } + getClipNames(seq, sequences); + } + } + } + + function objectIsSequence() { + var isSequence = false; + + for (var s = 0; s < app.project.sequences.numSequences; s++) { + if (item.name === app.project.sequences[s].name) { + isSequence = true; + } + } + + return isSequence; + } + + // walk through bins recursively + function walkBins (item, source, rootBinCounter) { + var bin; + if (source === 'root') { // bin in root folder + bin = source.children[rootBinCounter]; + } else { // bin in other bin + bin = item; + + for (var i = 0; i < bin.children.numItems; i++) { // if bin contains bin(s) walk through them + walkBins(bin.children[i]); + } + // $.pype.log('Bin ' + bin.name + ' has ' + bin.numSequences + ' sequences ' ); + // var seqCounter = -1; + for (var j = 0; j < bin.numSequences; j++) { + // if(objectIsSequence(item)) {//objects of type can also be other objects such as titles, so check if it really is a sequence? + // not needed because getSequenceAt apparently only looks at sequences already? + var seq = bin.getSequenceAt(j); + // $.pype.log('\nSequence in bin, guid: ' + seq.guid ); + getClipNames(seq, sequences); + } + } + } + + // walk through sequences and video & audiotracks to find clip names in sequences + function getClipNames (seq, sequences) { + for (var k = 0; k < sequences.length; k++) { + // $.pype.log('getClipNames seq.guid ' + seq.guid ); + // $.pype.log(' getClipNames sequences[k].id ' + sequences[k].sequenceID ); + if (seq.guid === sequences[k].sequenceID) { + // $.pype.log('Sequence ' + seq.name + ' has ' + app.project.sequences[k].videoTracks.numTracks +' video tracks' ); + // $.pype.log('Sequence ' + seq.name + ' has ' + app.project.sequences[k].audioTracks.numTracks +' audio tracks' ); + + // VIDEO CLIPS IN SEQUENCES + for (var l = 0; l < sequences[k].videoTracks.numTracks; l++) { + var videoTrack = seq.getVideoTrackAt(l); + // $.pype.log(seq.name + ' has video track '+ videoTrack.name + ' at index ' + l); + var clipCounter = 0; + var numOfClips = app.project.sequences[k].videoTracks[l].clips.numTracks; + // $.pype.log('\n' + bin.name + ' ' + seq.name + ' ' + videoTrack.name + ' has ' + numOfClips + ' clips'); + for (var m = 0; m < numOfClips; m++) { + // var clip = app.project.sequences[k].videoTracks[l].clips[m]; + // $.pype.log('clips in video tracks: ' + m + ' - ' + clip); TrackItem, doesn't have name property + // if a clip was deleted and another one added, the index of the new one is one or more higher + while (clipCounter < numOfClips) { // undefined because of old clips + if (videoTrack.getItemAt(m).name) { + clipCounter++; + // $.pype.log('getClipNames ' + seq.name + ' ' + videoTrack.name + ' has ' + videoTrack.getItemAt(m).name); Object + + for (var s = 0; s < sequences.length; s++) { + if (seq.guid === sequences[s].sequenceID) { + sequences[s].clipNames.push(videoTrack.getItemAt(m).name); + } + } + } + m++; + } + } + } + // $.pype.log('jsx after video loop clipsInSequences:' + clipsInSequences); + + // AUDIO CLIPS IN SEQUENCES + for (var l = 0; l < sequences[k].audioTracks.numTracks; l++) { + var audioTrack = seq.getAudioTrackAt(l); + // $.pype.log(bin.name + ' ' + seq.name + ' has audio track '+ audioTrack.name + ' at index ' + l); + // $.pype.log('\n' + bin.name + ' ' + seq.name + ' ' + audioTrack.name + ' has ' + app.project.sequences[k].audioTracks[l].clips.numTracks + ' clips'); + clipCounter = 0; + numOfClips = app.project.sequences[k].audioTracks[l].clips.numTracks; + + for (var m = 0; m < numOfClips; m++) { + var clip = app.project.sequences[k].audioTracks[l].clips[m]; + $.pype.log('clips in audio tracks: ' + m + ' - ' + clip); + // if a clip was deleted and another one added, the index of the new one is one or more higher + while (clipCounter < numOfClips) { // undefined because of old clips + if (audioTrack.getItemAt(m).name) { + clipCounter++; + // $.pype.log(seq.name + ' ' + audioTrack.name + ' has ' + audioTrack.getItemAt(m).name); + + for (var s = 0; s < sequences.length; s++) { + if (seq.guid === sequences[s].sequenceID) { + sequences[s].clipNames.push(audioTrack.getItemAt(m).name); + } + } + } + m++; + } + } + } + } // end if + } // end for + } // end getClipNames + + $.pype.log('sequences returned:' + sequences); + // return result to ReplaceService.js + var obj = { + data: sequences + }; + // $.pype.log('jsx getClipNames obj:' + obj); + return JSON.stringify(obj); + }, + + getProjectItems: function () { + var projectItems = []; + + var rootFolder = app.project.rootItem; + // walk through root folder of project to differentiate between bins, sequences and clips + for (var i = 0; i < rootFolder.children.numItems; i++) { + // $.pype.log('\nroot item at ' + i + " is of type " + rootFolder.children[i].type); + var item = rootFolder.children[i]; + + if (item.type === 2) { // bin + // $.pype.log('\n' ); + $.pype.getProjectItems.walkBins(item); + } else if (item.type === 1 && item.getMediaPath()) { // clip in root + // $.pype.log('Root folder has ' + item + ' ' + item.name); + projectItems.push(item); + } + } + + // walk through bins recursively + function walkBins (bin) { // eslint-disable-line no-unused-vars + + // $.writeln('bin.name + ' has ' + bin.children.numItems); + for (var i = 0; i < bin.children.numItems; i++) { + var object = bin.children[i]; + // $.pype.log(bin.name + ' has ' + object + ' ' + object.name + ' of type ' + object.type + ' and has mediapath ' + object.getMediaPath() ); + if (object.type === 2) { // bin + // $.pype.log(object.name + ' has ' + object.children.numItems ); + for (var j = 0; j < object.children.numItems; j++) { + var obj = object.children[j]; + if (obj.type === 1 && obj.getMediaPath()) { // clip in sub bin + // $.pype.log(object.name + ' has ' + obj + ' ' + obj.name ); + projectItems.push(obj); + } else if (obj.type === 2) { // bin + walkBins(obj); + } + } + } else if (object.type === 1 && object.getMediaPath()) { // clip in bin in root + // $.pype.log(bin.name + ' has ' + object + ' ' + object.name ); + projectItems.push(object); + } + } + } + $.pype.log('\nprojectItems:' + projectItems.length + ' ' + projectItems); + return projectItems; + }, + + getImageSize: function () { + return {h: app.project.activeSequence.frameSizeHorizontal, v: app.project.activeSequence.frameSizeVertical}; + }, + + getInOutOfAll: function () { + var seq = app.project.activeSequence; + var points = []; + var output = []; + + // VIDEO CLIPS IN SEQUENCES + for (var l = 0; l < seq.videoTracks.numTracks; l++) { + var numOfClips = seq.videoTracks[l].clips.numTracks; + // $.writeln('\n' + seq.name + ' ' + seq.videoTracks[l].name + ' has ' + numOfClips + ' clips'); + for (var m = 0; m < numOfClips; m++) { + var clip = seq.videoTracks[l].clips[m]; + points.push(Math.ceil(clip.start.seconds * 1000) / 1000); + points.push(Math.ceil(clip.end.seconds * 1000) / 1000); + } + } + + points.sort(function (a, b) { + return a - b; + }); + + output.push(points[0]); + output.push(points[points.length - 1]); + + return output; + }, + + getSelectedItems: function () { + var seq = app.project.activeSequence; + var selected = []; + + // VIDEO CLIPS IN SEQUENCES + for (var l = 0; l < seq.videoTracks.numTracks; l++) { + var numOfClips = seq.videoTracks[l].clips.numTracks; + // $.writeln('\n' + seq.name + ' ' + seq.videoTracks[l].name + ' has ' + numOfClips + ' clips'); + for (var m = 0; m < numOfClips; m++) { + var clip = seq.videoTracks[l].clips[m]; + if (clip.isSelected()) { + selected.push({clip: clip, sequence: seq, videoTrack: seq.videoTracks[l], trackOrder: l}); + } + } + } + return selected; + }, + /** + * Set Pype metadata into sequence metadata using XMP. + * This is `hackish` way to get over premiere lack of addressing unique clip on timeline, + * so we cannot store data directly per clip. + * + * @param {Object} sequence - sequence object + * @param {Object} data - to be serialized and saved + */ + setSequencePypeMetadata: function (sequence, data) { // eslint-disable-line no-unused-vars + var kPProPrivateProjectMetadataURI = 'http://ns.adobe.com/premierePrivateProjectMetaData/1.0/'; + var metadata = sequence.projectItem.getProjectMetadata(); + var pypeData = 'pypeData'; + var xmp = new XMPMeta(metadata); + + app.project.addPropertyToProjectMetadataSchema(pypeData, 'Pype Data', 2); + + xmp.setProperty(kPProPrivateProjectMetadataURI, pypeData, JSON.stringify(data)); + + var str = xmp.serialize(); + sequence.projectItem.setProjectMetadata(str, [pypeData]); + + // test + var newMetadata = sequence.projectItem.getProjectMetadata(); + var newXMP = new XMPMeta(newMetadata); + var found = newXMP.doesPropertyExist(kPProPrivateProjectMetadataURI, pypeData); + if (!found) { + app.setSDKEventMessage('metadata not set', 'error'); + } + }, + /** + * Get Pype metadata from sequence using XMP. + * @param {Object} sequence + * @param {Bool} firstTimeRun + * @return {Object} + */ + getSequencePypeMetadata: function (sequence, firstTimeRun) { // eslint-disable-line no-unused-vars + var kPProPrivateProjectMetadataURI = 'http://ns.adobe.com/premierePrivateProjectMetaData/1.0/'; + var metadata = sequence.projectItem.getProjectMetadata(); + var pypeData = 'pypeData'; + var pypeDataN = 'Pype Data'; + var xmp = new XMPMeta(metadata); + var successfullyAdded = app.project.addPropertyToProjectMetadataSchema(pypeData, pypeDataN, 2); + var pypeDataValue = xmp.getProperty(kPProPrivateProjectMetadataURI, pypeData); + + $.pype.log('__ pypeDataValue: ' + pypeDataValue); + $.pype.log('__ firstTimeRun: ' + firstTimeRun); + $.pype.log('__ successfullyAdded: ' + successfullyAdded); + if ((pypeDataValue === undefined) && (firstTimeRun !== undefined)) { + var pyMeta = { + clips: {}, + tags: {} + }; + $.pype.log('__ pyMeta: ' + pyMeta); + $.pype.setSequencePypeMetadata(sequence, pyMeta); + pypeDataValue = xmp.getProperty(kPProPrivateProjectMetadataURI, pypeData); + return $.pype.getSequencePypeMetadata(sequence); + } else { + if (successfullyAdded === true) { + $.pype.log('__ adding {}'); + $.pype.setSequencePypeMetadata(sequence, {}); + } + if ((pypeDataValue === undefined) || (!Object.prototype.hasOwnProperty.call(JSON.parse(pypeDataValue), 'clips'))) { + $.pype.log('__ getSequencePypeMetadata: returning null'); + return null; + } else { + $.pype.log('__ getSequencePypeMetadata: returning data'); + return JSON.parse(pypeDataValue); + } + } + }, + /** + * Sets project presets into module's variable for other functions to use. + * @param inPresets {object} - dictionary object comming from js + * @return {bool}: true is success, false if not + */ + setProjectPreset: function (inPresets) { + // validating the incoming data are having `plugins` key + if (Object.prototype.hasOwnProperty.call(inPresets, 'plugins')) { + $.pype.presets = inPresets; + return true; + } else { + $.pype.alert_message('Presets are missing `plugins` key!'); + return false; + } + }, + /** + * Gets project presets from module's variable for other functions to use. + * @return {Object}: JSON string with presets dictionary or false if unsuccess + */ + getProjectPreset: function () { + if ($.pype.presets === null) { + $.pype.alert_message('Presets needs to be set before they could be required!'); + return false; + } else { + return JSON.stringify($.pype.presets); + } + }, + /** + * Return instance representation of clip + * @param clip {object} - index of clip on videoTrack + * @param sequence {object Sequence} - Sequence clip is in + * @param videoTrack {object VideoTrack} - VideoTrack clip is in + * @return {Object} + */ + getClipAsInstance: function (clip, sequence, videoTrack, pypeData) { + var presets = JSON.parse($.pype.getProjectPreset()); + if ((clip.projectItem.type !== ProjectItemType.CLIP) && (clip.mediaType !== 'Video')) { + return false; + } + var pdClips = pypeData.clips; + var hierarchy; + var parents; + $.pype.log('>> getClipAsInstance:clip.name ' + clip.name); + if (pdClips[clip.name]) { + parents = pdClips[clip.name].parents; + hierarchy = pdClips[clip.name].hierarchy; + } + + if (hierarchy === null) { + $.pype.alert_message('First you need to rename clip sequencially with hierarchy!\nUse `Pype Rename` extension', 'No hierarchy data available at clip ' + clip.name + '!', 'error'); + return; + } + + var interpretation = clip.projectItem.getFootageInterpretation(); + $.pype.log('>> getClipAsInstance:interpretation ' + interpretation); + var instance = {}; + instance.publish = true; + instance.family = 'clip'; + instance.name = clip.name; + instance.hierarchy = hierarchy; + instance.parents = parents; + instance.subsetToRepresentations = presets.premiere.rules_tasks.subsetToRepresentations; + // metadata + var metadata = {}; + // TODO: how to get colorspace clip info + metadata.colorspace = 'bt.709'; + var settings = sequence.getSettings(); + var sequenceSize = $.pype.getImageSize(); + metadata['ppro.videoTrack.name'] = videoTrack.name; + metadata['ppro.sequence.name'] = sequence.name; + metadata['ppro.source.fps'] = parseFloat(1 / interpretation.frameRate).toFixed(4); + metadata['ppro.timeline.fps'] = parseFloat(1 / settings.videoFrameRate.seconds).toFixed(4); + metadata['ppro.source.path'] = $.pype.convertPathString(clip.projectItem.getMediaPath()); + metadata['ppro.format.width'] = sequenceSize.h; + metadata['ppro.format.height'] = sequenceSize.v; + metadata['ppro.format.pixelaspect'] = parseFloat(interpretation.pixelAspectRatio).toFixed(4); + metadata['ppro.source.start'] = clip.inPoint.seconds; + metadata['ppro.source.end'] = clip.outPoint.seconds; + metadata['ppro.source.duration'] = clip.duration.seconds; + metadata['ppro.clip.start'] = clip.start.seconds; + metadata['ppro.clip.end'] = clip.end.seconds; + + $.pype.log('>> getClipAsInstance:reprs ' + JSON.stringify(instance.subsetToRepresentations)); + + // set metadata to instance + instance.metadata = metadata; + return instance; + }, + + getSelectedClipsAsInstances: function () { + // get project script version and add it into clip instance data + var version = $.pype.getWorkFileVersion(); + $.pype.log('__ getSelectedClipsAsInstances:version: ' + version); + + var pypeData = $.pype.getSequencePypeMetadata(app.project.activeSequence); + $.pype.log( + '__ getSelectedClipsAsInstances:typeof(pypeData): ' + typeof (pypeData)); + $.pype.log('__ getSelectedClipsAsInstances:pypeData: ' + JSON.stringify(pypeData)); + + // check if the pype data are available and if not alert the user + // we need to have avalable metadata for correct hierarchy + if (pypeData === null) { + $.pype.alert_message('First you need to rename clips sequencially with hierarchy!\nUse `Pype Rename` extension, or use the above rename text layer section of `Pype` panel.\n\n>> No hierarchy data available! <<'); + return null; + } + + // instances + var instances = []; + var selected = $.pype.getSelectedItems(); + for (var s = 0; s < selected.length; s++) { + $.pype.log('__ getSelectedClipsAsInstances:selected[s].clip: ' + selected[s].clip); + var instance = $.pype.getClipAsInstance(selected[s].clip, selected[s].sequence, selected[s].videoTrack, pypeData); + if (instance !== false) { + instance.version = version; + instances.push(instance); + } + } + + // adding project file instance + var projectFileData = JSON.parse($.pype.getProjectFileData()); + var projectFileInstance = projectFileData; + projectFileInstance.subsetToRepresentations = { + workfile: { + representation: 'prproj' + } + }; + projectFileInstance.name = projectFileData.projectfile.split('.')[0]; + projectFileInstance.publish = true; + projectFileInstance.family = 'workfile'; + projectFileInstance.version = version; + instances.push(projectFileInstance); + + return instances; + }, + /** + * Return request json data object with instances for pyblish + * @param stagingDir {string} - path to temp directory + * @return {json string} + */ + getPyblishRequest: function (stagingDir, audioOnly) { + try { + var sequence = app.project.activeSequence; + var settings = sequence.getSettings(); + $.pype.log('__ stagingDir: ' + stagingDir); + $.pype.log('__ audioOnly: ' + audioOnly); + $.pype.log('__ sequence: ' + sequence); + $.pype.log('__ settings: ' + settings); + var request = { + stagingDir: stagingDir, + currentFile: $.pype.convertPathString(app.project.path), + framerate: (1 / settings.videoFrameRate.seconds), + host: $.getenv('AVALON_APP'), + hostVersion: $.getenv('AVALON_APP_NAME').split('_')[1], + cwd: $.pype.convertPathString(app.project.path).split('\\').slice(0, -1).join('\\') + }; + var sendInstances = []; + var instances = $.pype.getSelectedClipsAsInstances(); + + // make sure the process will end if no instancess are returned + if (instances === null) { + return null; + } + if (audioOnly === true) { + $.pype.log('? looping if audio True'); + for (var i = 0; i < instances.length; i++) { + var subsetToRepresentations = instances[i].subsetToRepresentations; + var newRepr = {}; + for (var key in subsetToRepresentations) { + var _include = ['audio', 'thumbnail', 'workfile']; + if (include(_include, key)) { + newRepr[key] = subsetToRepresentations[key]; + } + } + instances[i].subsetToRepresentations = newRepr; + sendInstances.push(instances[i]); + } + } else { + sendInstances = instances; + } + request.instances = sendInstances; + return JSON.stringify(request); + } catch (error) { + $.pype.log('error: ' + error); + return error; + } + }, + + // convertSecToTimecode: function (timeSec, fps) { + // var ceiled = Math.round(timeSec * 100) / 100; + // var parts = ('' + ceiled).split('.'); + // var dec = Number(parts[1]); + // var main = Number(parts[0]); + // var sec; + // var frames = (Number(('' + ( + // (dec * fps) / 100)).split('.')[0])).pad(2); + // if (main > 59) { + // sec = (Math.round(((Number(('' + ( + // Math.round((main / 60) * 100) / 100).toFixed(2)).split('.')[1]) / 100) * 60))).pad(2); + // if (sec === 'NaN') { + // sec = '00'; + // }; + // } else { + // sec = main; + // }; + // var min = (Number(('' + ( + // main / 60)).split('.')[0])).pad(2); + // var hov = (Number(('' + ( + // main / 3600)).split('.')[0])).pad(2); + // + // return hov + ':' + min + ':' + sec + ':' + frames; + // }, + + // exportThumbnail: function (name, family, version, outputPath, time, fps) { + // app.enableQE(); + // var activeSequence = qe.project.getActiveSequence(); // note: make sure a sequence is active in PPro UI + // var file = name + '_' + family + '_v' + version + '.jpg'; + // var fullPathToFile = outputPath + $._PPP_.getSep() + file; + // var expJPEG = activeSequence.exportFrameJPEG($.pype.convertSecToTimecode(time, fps), $.pype.convertPathString(fullPathToFile).split('/').join($._PPP_.getSep())); + // return file; + // }, + + encodeRepresentation: function (request) { + $.pype.log('__ request: ' + JSON.stringify(request)); + var sequence = app.project.activeSequence + // get original timeline in out points + var defaultTimelinePointValue = -400000 + var origInPoint = Math.ceil(sequence.getInPoint() * 100) / 100; + var origOutPoint = Math.ceil(sequence.getOutPoint() * 100) / 100; + if (origInPoint === defaultTimelinePointValue) { + var allInOut = $.pype.getInOutOfAll(); + origInPoint = allInOut[0]; + origOutPoint = allInOut[1]; + }; + $.pype.log('__ origInPoint: ' + origInPoint); + $.pype.log('__ origOutPoint: ' + origOutPoint); + + // instances + var instances = request.instances; + $.pype.log('__ instances: ' + JSON.stringify(instances)); + + for (var i = 0; i < instances.length; i++) { + // generate data for instance.subset representations + // loop representations of instance.subset and sent job to encoder + var subsetToRepresentations = instances[i].subsetToRepresentations; + $.pype.log('__ subsetToRepresentations: ' + subsetToRepresentations); + instances[i].files = []; + for (var key in subsetToRepresentations) { + $.pype.log('representation: ' + key); + // send render jobs to encoder + var exclude = ['workfile', 'thumbnail']; + if (!include(exclude, key)) { + instances[i].files.push( + $.pype.render( + request.stagingDir, + key, + subsetToRepresentations[key], + instances[i].name, + instances[i].version, + instances[i].metadata['ppro.clip.start'], + instances[i].metadata['ppro.clip.end'] + )); + } else if (key === 'thumbnail') { + // // create time to be in middle of clip + // var thumbStartTime = (instances[i].metadata['ppro.clip.start'] + ((instances[i].metadata['ppro.clip.end'] - instances[i].metadata['ppro.clip.start']) / 2)); + var thumbStartTime = instances[i].metadata['ppro.clip.start'] * 100; + + var thumbEndTime = Number( + thumbStartTime + ((1 / instances[i].metadata['ppro.timeline.fps']) * 100)); + + $.pype.log('_ thumbStartTime: ' + thumbStartTime); + $.pype.log('_ thumbEndTime: ' + thumbEndTime); + + // add instance of thumbnail + instances[i].files.push( + $.pype.render( + request.stagingDir, + key, + subsetToRepresentations[key], + instances[i].name, + instances[i].version, + Number(parseFloat(thumbStartTime / 100).toFixed(2)), + Number(parseFloat(thumbEndTime / 100).toFixed(2)) + ) + ); + } else if (key === 'workfile') { + instances[i].files.push(instances[i].projectfile); + }; + } + } + app.encoder.startBatch(); + // set back original in/out point on timeline + app.project.activeSequence.setInPoint(origInPoint); + app.project.activeSequence.setOutPoint(origOutPoint); + return JSON.stringify(request); + }, + + onEncoderJobComplete: function (jobID, outputFilePath) { + // remove job from expected jobs list + const index = $.pype.expectedJobs.indexOf(jobID); + if (index > -1) { + $.pype.expectedJobs.splice(index, 1); + } + + // test if expected job list is empty. If so, emit event for JS + if ($.pype.expectedJobs.length == 0) { + $.pype.log("encoding jobs finished."); + var eventObj = new CSXSEvent(); + eventObj.type = 'pype.EncoderJobsComplete'; + eventObj.data = {"jobID": jobID, "outputFilePath": outputFilePath}; + eventObj.dispatch(); + } + }, + + render: function (outputPath, family, representation, clipName, version, inPoint, outPoint) { + $.pype.log("_ inPoint: " + inPoint) + $.pype.log("_ outPoint: " + outPoint) + var outputPresetPath = $.getenv('EXTENSION_PATH').split('/').concat([ + 'encoding', + (representation.preset + '.epr') + ]).join($._PPP_.getSep()); + + + var activeSequence = app.project.activeSequence; + $.pype.log('launching encoder ... ' + family + ' ' + clipName); + if (activeSequence) { + app.encoder.launchEncoder(); // This can take a while; let's get the ball rolling. + + var projPath = new File(app.project.path); + + if ((outputPath) && projPath.exists) { + var outPreset = new File(outputPresetPath); + if (outPreset.exists === true) { + var outputFormatExtension = activeSequence.getExportFileExtension(outPreset.fsName); + if (outputFormatExtension) { + app.project.activeSequence.setInPoint(inPoint); + app.project.activeSequence.setOutPoint(outPoint); + var file = clipName + '_' + family + '_v' + version + '.' + outputFormatExtension; + var fullPathToFile = outputPath + $._PPP_.getSep() + file; + + var outFileTest = new File(fullPathToFile); + + if (outFileTest.exists) { + var destroyExisting = confirm('A file with that name already exists; overwrite?', false, 'Are you sure...?'); + if (destroyExisting) { + outFileTest.remove(); + outFileTest.close(); + } + } + + $.pype.log('binding events ...'); + app.encoder.bind('onEncoderJobComplete', $.pype.onEncoderJobComplete); + + // use these 0 or 1 settings to disable some/all metadata creation. + app.encoder.setSidecarXMPEnabled(0); + app.encoder.setEmbeddedXMPEnabled(0); + + $.pype.log('adding job to encoder'); + var jobID = app.encoder.encodeSequence(app.project.activeSequence, fullPathToFile, outPreset.fsName, app.encoder.ENCODE_IN_TO_OUT, 1); // Remove from queue upon successful completion? + $.pype.expectedJobs.push(jobID); + $.pype.log('job queue length: ' + $.pype.expectedJobs.length); + $._PPP_.updateEventPanel('jobID = ' + jobID); + outPreset.close(); + if (family === 'thumbnail') { + return clipName + '_' + family + '_v' + version + '0.' + outputFormatExtension; + } else { + return file; + } + } + } else { + $._PPP_.updateEventPanel('Could not find output preset.'); + } + } else { + $._PPP_.updateEventPanel('Could not find/create output path.'); + } + projPath.close(); + } else { + $._PPP_.updateEventPanel('No active sequence.'); + } + }, + + log: function (message) { + $.writeln(message); + message = JSON.stringify(message); + if (message.length > 100) { + message = message.slice(0, 100); + } + app.setSDKEventMessage(message, 'info'); + }, + + message: function (msg) { + $.writeln(msg); // Using '$' object will invoke ExtendScript Toolkit, if installed. + }, + + alert_message: function (message) { + alert(message, 'WARNING', true); + app.setSDKEventMessage(message, 'error'); + }, + + getWorkFileVersion: function () { + var outputPath = $.pype.convertPathString(app.project.path); + var outputName = String(app.project.name); + var dirPath = outputPath.replace(outputName, ''); + var pattern = /_v([0-9]*)/g; + var search = pattern.exec(outputName); + var version = 1; + var newFileName, + absPath; + + if (search) { + return search[1] + } else { + var create = confirm('The project file name is missing version `_v###` \n example: `NameOfFile_v001.prproj`\n\n Would you like to create version?', true, 'ERROR in name syntax'); + if (create) { + var splitName = outputName.split('.'); + newFileName = splitName[0] + '_v001.' + splitName[1]; + absPath = dirPath + newFileName; + app.project.saveAs(absPath.split('/').join($._PPP_.getSep())); + return '001'; + } + } + }, + + nextVersionCheck: function (dir, file, vCurVersStr, curVersStr, padding, nextVersNum) { + var replVers = vCurVersStr.replace(curVersStr, (nextVersNum).pad(padding)); + var newFileName = file.replace(vCurVersStr, replVers); + var absPath = dir + newFileName; + var absPathF = new File(absPath); + if (absPathF.exists) { + return $.pype.nextVersionCheck(dir, file, vCurVersStr, curVersStr, padding, (nextVersNum + 1)); + } else { + return absPathF + } + }, + + versionUpWorkFile: function () { + var outputPath = $.pype.convertPathString(app.project.path); + var outputName = String(app.project.name); + var dirPath = outputPath.replace(outputName, ''); + var pattern = /_v([0-9]*)/g; + var search = pattern.exec(outputName); + var version = 1; + var newFileName, + absPath; + + if (search) { + var match = parseInt(search[1], 10); + var padLength = search[1].length; + version += match; + var replVers = search[0].replace(search[1], (version).pad(padLength)); + newFileName = outputName.replace(search[0], replVers); + absPath = dirPath + newFileName; + + // check if new file already exists and offer confirmation + var absPathF = new File(absPath); + if (absPathF.exists) { + var overwrite = confirm('The file already exists! Do you want to overwrite it? NO: will save it as next available version', false, 'Are you sure...?'); + if (overwrite) { + // will overwrite + app.project.saveAs(absPath.split('/').join($._PPP_.getSep())); + return newFileName; + } else { + // will not overwrite + // will find next available version + absPathF = $.pype.nextVersionCheck(dirPath, outputName, search[0], search[1], padLength, (version + 1)); + absPath = $.pype.convertPathString(absPathF.fsName) + newFileName = absPath.replace(dirPath, '') + $.writeln('newFileName: ' + newFileName) + // will save it as new file + app.project.saveAs(absPath.split('/').join($._PPP_.getSep())); + return newFileName; + }; + } else { + app.project.saveAs(absPath.split('/').join($._PPP_.getSep())); + return newFileName; + }; + } else { + var create = confirm('The project file name is missing version `_v###` \n example: `NameOfFile_v001.prproj`\n\n Would you like to create version?", true, "ERROR in name syntax'); + if (create) { + var splitName = outputName.split('.'); + newFileName = splitName[0] + '_v001.' + splitName[1]; + absPath = dirPath + newFileName; + app.project.saveAs(absPath.split('/').join($._PPP_.getSep())); + return newFileName; + } + } + }, + // , + /** + * ####################################################################### + * bellow section is dedicated mostly to loading clips + * ####################################################################### + */ + + // replaceClips: function (obj, projectItems) { + // $.pype.log('num of projectItems:' + projectItems.length); + // var hiresVOs = obj.hiresOnFS; + // for (var i = 0; i < hiresVOs.length; i++) { + // $.pype.log('hires vo name: ' + hiresVOs[i].name); + // $.pype.log('hires vo id: ' + hiresVOs[i].id); + // $.pype.log('hires vo path: ' + hiresVOs[i].path); + // $.pype.log('hires vo replace: ' + hiresVOs[i].replace); + // + // for (var j = 0; j < projectItems.length; j++) { + // // $.pype.log('projectItem id: ' + projectItems[j].name.split(' ')[0] + ' ' + hiresVOs[i].id + ' can change path ' + projectItems[j].canChangeMediaPath() ); + // if (projectItems[j].name.split(' ')[0] === hiresVOs[i].id && hiresVOs[i].replace && projectItems[j].canChangeMediaPath()) { + // $.pype.log('replace: ' + projectItems[j].name + ' with ' + hiresVOs[i].name); + // projectItems[j].name = hiresVOs[i].name; + // projectItems[j].changeMediaPath(hiresVOs[i].path); + // } + // } + // } + // }, + + // addNewTrack: function (numTracks) { + // app.enableQE(); + // var sequence = app.project.activeSequence; + // var activeSequence = qe.project.getActiveSequence(); + // activeSequence.addTracks(numTracks, sequence.videoTracks.numTracks, 0); + // + // for (var t = 0; t < sequence.videoTracks.numTracks; t++) { + // var videoTrack = sequence.videoTracks[t]; + // var trackName = videoTrack.name; + // var trackTarget = videoTrack.isTargeted(); + // // $.writeln(trackTarget); + // sequence.videoTracks[t].setTargeted(false, true); + // trackTarget = videoTrack.isTargeted(); + // // $.writeln(trackTarget); + // // $.writeln(videoTrack); + // } + // }, + + // searchForBinWithName: function (nameToFind, folderObject) { + // // deep-search a folder by name in project + // var deepSearchBin = function (inFolder) { + // if (inFolder && inFolder.name === nameToFind && inFolder.type === 2) { + // return inFolder; + // } else { + // for (var i = 0; i < inFolder.children.numItems; i++) { + // if (inFolder.children[i] && inFolder.children[i].type === 2) { + // var foundBin = deepSearchBin(inFolder.children[i]); + // if (foundBin) + // return foundBin; + // } + // } + // } + // return undefined; + // }; + // if (folderObject === undefined) { + // return deepSearchBin(app.project.rootItem); + // } else { + // return deepSearchBin(folderObject); + // } + // }, + + // createDeepBinStructure: function (hierarchyString) { + // var parents = hierarchyString.split('/'); + // + // // search for the created folder + // var currentBin = $.pype.searchForBinWithName(parents[0]); + // // create bin if doesn't exists + // if (currentBin === undefined) { + // currentBin = app.project.rootItem.createBin(parents[0]); + // } + // for (var b = 1; b < parents.length; b++) { + // var testBin = $.pype.searchForBinWithName(parents[b], currentBin); + // if (testBin === undefined) { + // currentBin = currentBin.createBin(parents[b]); + // } else { + // currentBin = testBin; + // } + // } + // return currentBin; + // }, + + // insertBinClipToTimeline: function (binClip, time, trackOrder, numTracks, origNumTracks) { + // var seq = app.project.activeSequence; + // var numVTracks = seq.videoTracks.numTracks; + // + // var addInTrack = (numTracks === 1) + // ? (origNumTracks) + // : (numVTracks - numTracks + trackOrder); + // $.writeln('\n___name: ' + binClip.name); + // $.writeln('numVTracks: ' + numVTracks + ', trackOrder: ' + trackOrder + ', numTracks: ' + numTracks + ', origNumTracks: ' + origNumTracks + ', addInTrack: ' + addInTrack); + // + // var targetVTrack = seq.videoTracks[addInTrack]; + // + // if (targetVTrack) { + // targetVTrack.insertClip(binClip, time); + // } + // }, + // /** + // * Return instance representation of clip imported into bin + // * @param data {object} - has to have at least two attributes `clips` and `binHierarchy` + // * @return {Object} + // */ + + // importFiles: function (data) { + // // remove all empty tracks + // app.enableQE(); + // var activeSequence = qe.project.getActiveSequence(); + // activeSequence.removeEmptyVideoTracks(); + // activeSequence.removeEmptyAudioTracks(); + // + // if (app.project) { + // if (data !== undefined) { + // var pathsToImport = []; + // var namesToGetFromBin = []; + // var namesToSetToClips = []; + // var origNumTracks = app.project.activeSequence.videoTracks.numTracks; + // // TODO: for now it always creates new track and adding it into it + // $.pype.addNewTrack(data.numTracks); + // + // // get all paths and names list + // var key = ''; + // for (key in data.clips) { + // var path = data.clips[key]['data']['path']; + // var fileName = path.split('/'); + // if (fileName.length <= 1) { + // fileName = path.split('\\'); + // } + // fileName = fileName[fileName.length - 1]; + // pathsToImport.push(path); + // namesToGetFromBin.push(fileName); + // namesToSetToClips.push(key); + // } + // + // // create parent bin object + // var parent = $.pype.createDeepBinStructure(data.binHierarchy); + // + // // check if any imported clips are in the bin + // if (parent.children.numItems > 0) { + // // loop pathsToImport + // var binItemNames = []; + // for (var c = 0; c < parent.children.numItems; c++) { + // binItemNames.push(parent.children[c].name); + // } + // + // // loop formated clip names to be imported + // for (var p = 0; p < namesToSetToClips.length; p++) { + // // check if the clip is not in bin items alrady + // if (!include(binItemNames, namesToSetToClips[p])) { + // app.project.importFiles([pathsToImport[p]], 1, // suppress warnings + // parent, 0); // import as numbered stills + // + // for (var pi = 0; pi < parent.children.numItems; pi++) { + // if (namesToGetFromBin[p] === parent.children[pi].name) { + // parent.children[pi].name = namesToSetToClips[p]; + // var start = data.clips[namesToSetToClips[p]]['parentClip']['start'] + // $.pype.insertBinClipToTimeline(parent.children[pi], start, data.clips[namesToSetToClips[p]]['parentClip']['trackOrder'], data.numTracks, origNumTracks); + // } + // } + // } else { // if the bin item already exist just update the path + // // loop children in parent bin + // for (var pi = 0; pi < parent.children.numItems; pi++) { + // if (namesToSetToClips[p] === parent.children[pi].name) { + // $.writeln('__namesToSetToClips[p]__: ' + namesToSetToClips[p]); + // parent.children[pi].changeMediaPath(pathsToImport[p]); + // // clip exists and we can update path + // $.writeln('____clip exists and updating path'); + // } + // } + // } + // } + // } else { + // app.project.importFiles(pathsToImport, 1, // suppress warnings + // parent, 0); // import as numbered stills + // for (var pi = 0; pi < parent.children.numItems; pi++) { + // parent.children[pi].name = namesToSetToClips[i]; + // start = data.clips[namesToSetToClips[i]]['parentClip']['start'] + // $.pype.insertBinClipToTimeline(parent.children[pi], start, data.clips[namesToSetToClips[i]]['parentClip']['trackOrder'], data.numTracks, origNumTracks); + // } + // + // return; + // } + // } else { + // alert('Missing data for clip insertion', 'error'); + // return false; + // } + // } + // // remove all empty tracks + // activeSequence.removeEmptyVideoTracks(); + // activeSequence.removeEmptyAudioTracks(); + // } +}; + +Number.prototype.pad = function (size) { + var s = String(this); + while (s.length < (size || 2)) { + s = "0" + s; + } + return s; +}; + +function include (arr, obj) { + for (var i = 0; i < arr.length; i++) { + if (arr[i] === obj) + return true; + } + return false +} diff --git a/pype/premiere/extensions/com.pype/jsx/testingCode._jsx b/pype/premiere/extensions/com.pype/jsx/testingCode._jsx new file mode 100644 index 00000000000..282d6374e97 --- /dev/null +++ b/pype/premiere/extensions/com.pype/jsx/testingCode._jsx @@ -0,0 +1,11 @@ +var extensionFolder = new Folder( + 'C:/Users/jezsc/CODE/pype-setup/repos/pype/pype/premiere/extensions/com.pype'); +$.writeln(extensionFolder); +var mainJsx = extensionFolder + '/pypeApp.jsx'; +$.evalFile(mainJsx); +var appName = 'PPRO'; +$._ext.evalJSXFiles(extensionFolder, appName); +$._ext.evalJSFiles(extensionFolder); +/////////////////////////////////////////////////////////////////////////////////////////////////////////// + +$.pype.getSequencePypeMetadata(app.project.activeSequence); diff --git a/pype/premiere/extensions/com.pype/lib/CEPEngine_extensions.js b/pype/premiere/extensions/com.pype/lib/CEPEngine_extensions.js new file mode 100644 index 00000000000..04f5516a2d6 --- /dev/null +++ b/pype/premiere/extensions/com.pype/lib/CEPEngine_extensions.js @@ -0,0 +1,699 @@ +/************************************************************************************************** +* +* ADOBE SYSTEMS INCORPORATED +* Copyright 2013 Adobe Systems Incorporated +* All Rights Reserved. +* +* NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the +* terms of the Adobe license agreement accompanying it. If you have received this file from a +* source other than Adobe, then your use, modification, or distribution of it requires the prior +* written permission of Adobe. +* +**************************************************************************************************/ + +// This is the JavaScript code for bridging to native functionality +// See CEPEngine_extensions.cpp for implementation of native methods. +// +// Note: So far all native file i/o functions are synchronous, and aynchronous file i/o is TBD. + +/** Version v8.0.0 */ + +/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, forin: true, maxerr: 50, regexp: true */ +/*global define, native */ + +var cep; +if (!cep) { + cep = {}; +} +if (!cep.fs) { + cep.fs = {}; +} +if (!cep.process) { + cep.process = {}; +} +if (!cep.encoding) { + cep.encoding = {}; +} +if (!cep.util) { + cep.util = {}; +} +(function () { + // Internal function to get the last error code. + native function GetLastError(); + function getLastError() { + return GetLastError(); + } + + function getErrorResult(){ + var result = {err: getLastError()}; + return result; + } + + // Error values. These MUST be in sync with the error values + // at the top of CEPEngine_extensions.cpp + + /** + * @constant No error. + */ + cep.fs.NO_ERROR = 0; + + /** + * @constant Unknown error occurred. + */ + cep.fs.ERR_UNKNOWN = 1; + + /** + * @constant Invalid parameters passed to function. + */ + cep.fs.ERR_INVALID_PARAMS = 2; + + /** + * @constant File or directory was not found. + */ + cep.fs.ERR_NOT_FOUND = 3; + + /** + * @constant File or directory could not be read. + */ + cep.fs.ERR_CANT_READ = 4; + + /** + * @constant An unsupported encoding value was specified. + */ + cep.fs.ERR_UNSUPPORTED_ENCODING = 5; + + /** + * @constant File could not be written. + */ + cep.fs.ERR_CANT_WRITE = 6; + + /** + * @constant Target directory is out of space. File could not be written. + */ + cep.fs.ERR_OUT_OF_SPACE = 7; + + /** + * @constant Specified path does not point to a file. + */ + cep.fs.ERR_NOT_FILE = 8; + + /** + * @constant Specified path does not point to a directory. + */ + cep.fs.ERR_NOT_DIRECTORY = 9; + + /** + * @constant Specified file already exists. + */ + cep.fs.ERR_FILE_EXISTS = 10; + + /** + * @constant The maximum number of processes has been exceeded. + */ + cep.process.ERR_EXCEED_MAX_NUM_PROCESS = 101; + + /** + * @constant Invalid URL. + */ + cep.util.ERR_INVALID_URL = 201; + + /** + * @constant deprecated API. + */ + cep.util.DEPRECATED_API = 202; + + /** + * @constant UTF8 encoding type. + */ + cep.encoding.UTF8 = "UTF-8"; + + /** + * @constant Base64 encoding type. + */ + cep.encoding.Base64 = "Base64"; + + /** + * Displays the OS File Open dialog, allowing the user to select files or directories. + * + * @param allowMultipleSelection {boolean} When true, multiple files/folders can be selected. + * @param chooseDirectory {boolean} When true, only folders can be selected. When false, only + * files can be selected. + * @param title {string} Title of the open dialog. + * @param initialPath {string} Initial path to display in the dialog. Pass NULL or "" to + * display the last path chosen. + * @param fileTypes {Array.} The file extensions (without the dot) for the types + * of files that can be selected. Ignored when chooseDirectory=true. + * + * @return An object with these properties: + *
  • "data": An array of the full names of the selected files.
  • + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_INVALID_PARAMS
  • + *
+ **/ + native function ShowOpenDialog(); + cep.fs.showOpenDialog = function (allowMultipleSelection, chooseDirectory, title, initialPath, fileTypes) { + var resultString = ShowOpenDialog(allowMultipleSelection, chooseDirectory, + title || 'Open', initialPath || '', + fileTypes ? fileTypes.join(' ') : ''); + + var result = {data: JSON.parse(resultString || '[]'), err: getLastError() }; + return result; + }; + + /** + * Displays the OS File Open dialog, allowing the user to select files or directories. + * + * @param allowMultipleSelection {boolean} When true, multiple files/folders can be selected. + * @param chooseDirectory {boolean} When true, only folders can be selected. When false, only + * files can be selected. + * @param title {string} Title of the open dialog. + * @param initialPath {string} Initial path to display in the dialog. Pass NULL or "" to + * display the last path chosen. + * @param fileTypes {Array.} The file extensions (without the dot) for the types + * of files that can be selected. Ignored when chooseDirectory=true. + * @param friendlyFilePrefix {string} String to put in front of the extensions + * of files that can be selected. Ignored when chooseDirectory=true. (win only) + * For example: + * fileTypes = ["gif", "jpg", "jpeg", "png", "bmp", "webp", "svg"]; + * friendlyFilePrefix = "Images (*.gif;*.jpg;*.jpeg;*.png;*.bmp;*.webp;*.svg)"; + * @param prompt {string} String for OK button (mac only, default is "Open" on mac, "Open" or "Select Folder" on win). + * + * @return An object with these properties: + *
  • "data": An array of the full names of the selected files.
  • + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_INVALID_PARAMS
  • + *
+ **/ + native function ShowOpenDialogEx(); + cep.fs.showOpenDialogEx = function (allowMultipleSelection, chooseDirectory, title, initialPath, fileTypes, + friendlyFilePrefix, prompt) { + var resultString = ShowOpenDialogEx(allowMultipleSelection, chooseDirectory, + title || 'Open', initialPath || '', + fileTypes ? fileTypes.join(' ') : '', friendlyFilePrefix || '', + prompt || ''); + + var result = {data: JSON.parse(resultString || '[]'), err: getLastError() }; + return result; + }; + + /** + * Displays the OS File Save dialog, allowing the user to type in a file name. + * + * @param title {string} Title of the save dialog. + * @param initialPath {string} Initial path to display in the dialog. Pass NULL or "" to + * display the last path chosen. + * @param fileTypes {Array.} The file extensions (without the dot) for the types + * of files that can be selected. + * @param defaultName {string} String to start with for the file name. + * @param friendlyFilePrefix {string} String to put in front of the extensions of files that can be selected. (win only) + * For example: + * fileTypes = ["gif", "jpg", "jpeg", "png", "bmp", "webp", "svg"]; + * friendlyFilePrefix = "Images (*.gif;*.jpg;*.jpeg;*.png;*.bmp;*.webp;*.svg)"; + * @param prompt {string} String for Save button (mac only, default is "Save" on mac and win). + * @param nameFieldLabel {string} String displayed in front of the file name text field (mac only, "File name:" on win). + * + * @return An object with these properties: + *
  • "data": The file path selected to save at or "" if canceled
  • + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_INVALID_PARAMS
  • + *
+ **/ + native function ShowSaveDialogEx(); + cep.fs.showSaveDialogEx = function (title, initialPath, fileTypes, defaultName, friendlyFilePrefix, prompt, nameFieldLabel) { + var resultString = ShowSaveDialogEx(title || '', initialPath || '', + fileTypes ? fileTypes.join(' ') : '', defaultName || '', + friendlyFilePrefix || '', prompt || '', nameFieldLabel || ''); + + var result = {data: resultString || '', err: getLastError() }; + return result; + }; + + /** + * Reads the contents of a folder. + * + * @param path {string} The path of the folder to read. + * + * @return An object with these properties: + *
  • "data": An array of the names of the contained files (excluding '.' and '..'.
  • + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_NOT_FOUND + *
    ERR_CANT_READ
+ **/ + native function ReadDir(); + cep.fs.readdir = function (path) { + var resultString = ReadDir(path); + var result = {data: JSON.parse(resultString || '[]'), err: getLastError() }; + return result; + }; + + /** + * Creates a new folder. + * + * @param path {string} The path of the folder to create. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS
+ **/ + native function MakeDir(); + cep.fs.makedir = function (path) { + MakeDir(path); + return getErrorResult(); + }; + + /** + * Renames a file or folder. + * + * @param oldPath {string} The old name of the file or folder. + * @param newPath {string} The new name of the file or folder. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_NOT_FOUND + *
    ERR_FILE_EXISTS
+ **/ + native function Rename(); + cep.fs.rename = function(oldPath, newPath) { + Rename(oldPath, newPath); + return getErrorResult(); + }; + + /** + * Reports whether an item is a file or folder. + * + * @param path {string} The path of the file or folder. + * + * @return An object with these properties: + *
  • "data": An object with properties + *
    isFile (boolean) + *
    isDirectory (boolean) + *
    mtime (modification DateTime)
  • + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_NOT_FOUND
  • + *
+ **/ + native function IsDirectory(); + native function GetFileModificationTime(); + cep.fs.stat = function (path) { + var isDir = IsDirectory(path); + var modtime = GetFileModificationTime(path); + var result = { + data: { + isFile: function () { + return !isDir; + }, + isDirectory: function () { + return isDir; + }, + mtime: modtime + }, + err: getLastError() + }; + + return result; + }; + + /** + * Reads the entire contents of a file. + * + * @param path {string} The path of the file to read. + * @param encoding {string} The encoding of the contents of file, one of + * UTF8 (the default) or Base64. + * + * @return An object with these properties: + *
  • "data": The file contents.
  • + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_NOT_FOUND + *
    ERR_CANT_READ + *
    ERR_UNSUPPORTED_ENCODING
  • + *
+ **/ + native function ReadFile(); + cep.fs.readFile = function (path, encoding) { + encoding = encoding ? encoding : cep.encoding.UTF8; + var contents = ReadFile(path, encoding); + var result = {data: contents, err: getLastError() }; + return result; + }; + + /** + * Writes data to a file, replacing the file if it already exists. + * + * @param path {string} The path of the file to write. + * @param data {string} The data to write to the file. + * @param encoding {string} The encoding of the contents of file, one of + * UTF8 (the default) or Base64. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_UNSUPPORTED_ENCODING + *
    ERR_CANT_WRITE + *
    ERR_OUT_OF_SPACE
+ **/ + native function WriteFile(); + cep.fs.writeFile = function (path, data, encoding) { + encoding = encoding ? encoding : cep.encoding.UTF8; + WriteFile(path, data, encoding); + return getErrorResult(); + }; + + /** + * Sets permissions for a file or folder. + * + * @param path {string} The path of the file or folder. + * @param mode {number} The permissions in numeric format (for example, 0777). + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_CANT_WRITE
+ **/ + native function SetPosixPermissions(); + cep.fs.chmod = function (path, mode) { + SetPosixPermissions(path, mode); + return getErrorResult(); + }; + + /** + * Deletes a file. + * + * @param path {string} The path of the file to delete. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_NOT_FOUND + *
    ERR_NOT_FILE
+ **/ + native function DeleteFileOrDirectory(); + native function IsDirectory(); + cep.fs.deleteFile = function (path) { + if (IsDirectory(path)) { + var result = {err: cep.fs.ERR_NOT_FILE}; + return result; + } + DeleteFileOrDirectory(path); + return getErrorResult(); + }; + + /** + * Creates a process. + * + * @param arguments {list} The arguments to create process. The first one is the full path of the executable, + * followed by the arguments of the executable. + * + * @return An object with these properties: + *
  • "data": The pid of the process, or -1 on error.
  • + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_EXCEED_MAX_NUM_PROCESS + *
    ERR_NOT_FOUND + *
    ERR_NOT_FILE
  • + *
+ **/ + native function CreateProcess(); + cep.process.createProcess = function () { + var args = Array.prototype.slice.call(arguments); + var pid = CreateProcess(args); + var result = {data: pid, err: getLastError()}; + return result; + }; + + /** + * Registers a standard-output handler for a process. + * + * @param pid {int} The pid of the process. + * @param callback {function} The handler function for the standard output callback. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_INVALID_PROCESS_ID
+ **/ + native function SetupStdOutHandler(); + cep.process.stdout = function (pid, callback) { + SetupStdOutHandler(pid, callback); + return getErrorResult(); + }; + + /** + * Registers up a standard-error handler for a process. + * + * @param pid {int} The pid of the process. + * @param callback {function} The handler function for the standard error callback. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_INVALID_PROCESS_ID
+ **/ + native function SetupStdErrHandler(); + cep.process.stderr = function (pid, callback) { + SetupStdErrHandler(pid, callback); + return getErrorResult(); + }; + + /** + * Writes data to the standard input of a process. + * + * @param pid {int} The pid of the process + * @param data {string} The data to write. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_INVALID_PROCESS_ID
+ **/ + native function WriteStdIn(); + cep.process.stdin = function (pid, data) { + WriteStdIn(pid, data); + return getErrorResult(); + }; + + /** + * Retrieves the working directory of a process. + * + * @param pid {int} The pid of the process. + * + * @return An object with these properties: + *
  • "data": The path of the working directory.
  • + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_INVALID_PROCESS_ID
+ **/ + native function GetWorkingDirectory(); + cep.process.getWorkingDirectory = function (pid) { + var wd = GetWorkingDirectory(pid); + var result = {data: wd, err: getLastError()}; + return result; + }; + + /** + * Waits for a process to quit. + * + * @param pid {int} The pid of the process. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_INVALID_PROCESS_ID
+ **/ + native function WaitFor(); + cep.process.waitfor = function (pid) { + WaitFor(pid); + return getErrorResult(); + }; + + /** + * Registers a handler for the onquit callback of a process. + * + * @param pid {int} The pid of the process. + * @param callback {function} The handler function. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_INVALID_PROCESS_ID
+ **/ + native function OnQuit(); + cep.process.onquit = function (pid, callback) { + OnQuit(pid, callback); + return getErrorResult(); + }; + + /** + * Reports whether a process is currently running. + * + * @param pid {int} The pid of the process. + * + * @return An object with these properties: + *
  • "data": True if the process is running, false otherwise.
  • + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_INVALID_PROCESS_ID
+ **/ + native function IsRunning(); + cep.process.isRunning = function (pid) { + var isRunning = IsRunning(pid); + var result = {data: isRunning, err: getLastError()}; + return result; + }; + + /** + * Terminates a process. + * + * @param pid {int} The pid of the process + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_INVALID_PROCESS_ID
+ **/ + native function Terminate(); + cep.process.terminate = function (pid) { + Terminate(pid); + return getErrorResult(); + }; + + /** + * Encoding conversions. + * + */ + cep.encoding.convertion = + { + utf8_to_b64: function(str) { + return window.btoa(unescape(encodeURIComponent(str))); + }, + + b64_to_utf8: function(base64str) { + // If a base64 string contains any whitespace character, DOM Exception 5 occurs during window.atob, please see + // http://stackoverflow.com/questions/14695988/dom-exception-5-invalid-character-error-on-valid-base64-image-string-in-javascri + base64str = base64str.replace(/\s/g, ''); + return decodeURIComponent(escape(window.atob(base64str))); + }, + + binary_to_b64: function(binary) { + return window.btoa(binary); + }, + + b64_to_binary: function(base64str) { + return window.atob(base64str); + }, + + ascii_to_b64: function(ascii) { + return window.btoa(binary); + }, + + b64_to_ascii: function(base64str) { + return window.atob(base64str); + } + }; + + /** + * Opens a page in the default system browser. + * + * @param url {string} The URL of the page/file to open, or the email address. + * Must use HTTP/HTTPS/file/mailto. For example: + * "http://www.adobe.com" + * "https://github.com" + * "file:///C:/log.txt" + * "mailto:test@adobe.com" + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS
+ **/ + native function OpenURLInDefaultBrowser(); + cep.util.openURLInDefaultBrowser = function (url) { + if (url && (url.indexOf("http://") === 0 || + url.indexOf("https://") === 0 || + url.indexOf("file://") === 0 || + url.indexOf("mailto:") === 0)) { + OpenURLInDefaultBrowser(url); + return getErrorResult(); + } else { + return { err : cep.util.ERR_INVALID_URL }; + } + }; + + /** + * Registers a callback function for extension unload. If called more than once, + * the last callback that is successfully registered is used. + * + * @deprecated since version 6.0.0 + * + * @param callback {function} The handler function. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_INVALID_PARAMS
+ **/ + native function RegisterExtensionUnloadCallback(); + cep.util.registerExtensionUnloadCallback = function (callback) { + return { err : cep.util.DEPRECATED_API }; + }; + + /** + * Stores the user's proxy credentials + * + * @param username {string} proxy username + * @param password {string} proxy password + * + * @return An object with this property: + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_INVALID_PARAMS
  • + *
+ **/ + native function StoreProxyCredentials(); + cep.util.storeProxyCredentials = function (username, password) { + StoreProxyCredentials(username, password); + return getErrorResult(); + }; + +})(); diff --git a/pype/premiere/extensions/com.pype/lib/CSInterface.js b/pype/premiere/extensions/com.pype/lib/CSInterface.js new file mode 100644 index 00000000000..e2a6e02eb21 --- /dev/null +++ b/pype/premiere/extensions/com.pype/lib/CSInterface.js @@ -0,0 +1,1291 @@ +/************************************************************************************************** +* +* ADOBE SYSTEMS INCORPORATED +* Copyright 2013 Adobe Systems Incorporated +* All Rights Reserved. +* +* NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the +* terms of the Adobe license agreement accompanying it. If you have received this file from a +* source other than Adobe, then your use, modification, or distribution of it requires the prior +* written permission of Adobe. +* +**************************************************************************************************/ + +/** CSInterface - v9.2.0 */ + +/** + * Stores constants for the window types supported by the CSXS infrastructure. + */ +function CSXSWindowType() +{ +} + +/** Constant for the CSXS window type Panel. */ +CSXSWindowType._PANEL = "Panel"; + +/** Constant for the CSXS window type Modeless. */ +CSXSWindowType._MODELESS = "Modeless"; + +/** Constant for the CSXS window type ModalDialog. */ +CSXSWindowType._MODAL_DIALOG = "ModalDialog"; + +/** EvalScript error message */ +EvalScript_ErrMessage = "EvalScript error."; + +/** + * @class Version + * Defines a version number with major, minor, micro, and special + * components. The major, minor and micro values are numeric; the special + * value can be any string. + * + * @param major The major version component, a positive integer up to nine digits long. + * @param minor The minor version component, a positive integer up to nine digits long. + * @param micro The micro version component, a positive integer up to nine digits long. + * @param special The special version component, an arbitrary string. + * + * @return A new \c Version object. + */ +function Version(major, minor, micro, special) +{ + this.major = major; + this.minor = minor; + this.micro = micro; + this.special = special; +} + +/** + * The maximum value allowed for a numeric version component. + * This reflects the maximum value allowed in PlugPlug and the manifest schema. + */ +Version.MAX_NUM = 999999999; + +/** + * @class VersionBound + * Defines a boundary for a version range, which associates a \c Version object + * with a flag for whether it is an inclusive or exclusive boundary. + * + * @param version The \c #Version object. + * @param inclusive True if this boundary is inclusive, false if it is exclusive. + * + * @return A new \c VersionBound object. + */ +function VersionBound(version, inclusive) +{ + this.version = version; + this.inclusive = inclusive; +} + +/** + * @class VersionRange + * Defines a range of versions using a lower boundary and optional upper boundary. + * + * @param lowerBound The \c #VersionBound object. + * @param upperBound The \c #VersionBound object, or null for a range with no upper boundary. + * + * @return A new \c VersionRange object. + */ +function VersionRange(lowerBound, upperBound) +{ + this.lowerBound = lowerBound; + this.upperBound = upperBound; +} + +/** + * @class Runtime + * Represents a runtime related to the CEP infrastructure. + * Extensions can declare dependencies on particular + * CEP runtime versions in the extension manifest. + * + * @param name The runtime name. + * @param version A \c #VersionRange object that defines a range of valid versions. + * + * @return A new \c Runtime object. + */ +function Runtime(name, versionRange) +{ + this.name = name; + this.versionRange = versionRange; +} + +/** +* @class Extension +* Encapsulates a CEP-based extension to an Adobe application. +* +* @param id The unique identifier of this extension. +* @param name The localizable display name of this extension. +* @param mainPath The path of the "index.html" file. +* @param basePath The base path of this extension. +* @param windowType The window type of the main window of this extension. + Valid values are defined by \c #CSXSWindowType. +* @param width The default width in pixels of the main window of this extension. +* @param height The default height in pixels of the main window of this extension. +* @param minWidth The minimum width in pixels of the main window of this extension. +* @param minHeight The minimum height in pixels of the main window of this extension. +* @param maxWidth The maximum width in pixels of the main window of this extension. +* @param maxHeight The maximum height in pixels of the main window of this extension. +* @param defaultExtensionDataXml The extension data contained in the default \c ExtensionDispatchInfo section of the extension manifest. +* @param specialExtensionDataXml The extension data contained in the application-specific \c ExtensionDispatchInfo section of the extension manifest. +* @param requiredRuntimeList An array of \c Runtime objects for runtimes required by this extension. +* @param isAutoVisible True if this extension is visible on loading. +* @param isPluginExtension True if this extension has been deployed in the Plugins folder of the host application. +* +* @return A new \c Extension object. +*/ +function Extension(id, name, mainPath, basePath, windowType, width, height, minWidth, minHeight, maxWidth, maxHeight, + defaultExtensionDataXml, specialExtensionDataXml, requiredRuntimeList, isAutoVisible, isPluginExtension) +{ + this.id = id; + this.name = name; + this.mainPath = mainPath; + this.basePath = basePath; + this.windowType = windowType; + this.width = width; + this.height = height; + this.minWidth = minWidth; + this.minHeight = minHeight; + this.maxWidth = maxWidth; + this.maxHeight = maxHeight; + this.defaultExtensionDataXml = defaultExtensionDataXml; + this.specialExtensionDataXml = specialExtensionDataXml; + this.requiredRuntimeList = requiredRuntimeList; + this.isAutoVisible = isAutoVisible; + this.isPluginExtension = isPluginExtension; +} + +/** + * @class CSEvent + * A standard JavaScript event, the base class for CEP events. + * + * @param type The name of the event type. + * @param scope The scope of event, can be "GLOBAL" or "APPLICATION". + * @param appId The unique identifier of the application that generated the event. + * @param extensionId The unique identifier of the extension that generated the event. + * + * @return A new \c CSEvent object + */ +function CSEvent(type, scope, appId, extensionId) +{ + this.type = type; + this.scope = scope; + this.appId = appId; + this.extensionId = extensionId; +} + +/** Event-specific data. */ +CSEvent.prototype.data = ""; + +/** + * @class SystemPath + * Stores operating-system-specific location constants for use in the + * \c #CSInterface.getSystemPath() method. + * @return A new \c SystemPath object. + */ +function SystemPath() +{ +} + +/** The path to user data. */ +SystemPath.USER_DATA = "userData"; + +/** The path to common files for Adobe applications. */ +SystemPath.COMMON_FILES = "commonFiles"; + +/** The path to the user's default document folder. */ +SystemPath.MY_DOCUMENTS = "myDocuments"; + +/** @deprecated. Use \c #SystemPath.Extension. */ +SystemPath.APPLICATION = "application"; + +/** The path to current extension. */ +SystemPath.EXTENSION = "extension"; + +/** The path to hosting application's executable. */ +SystemPath.HOST_APPLICATION = "hostApplication"; + +/** + * @class ColorType + * Stores color-type constants. + */ +function ColorType() +{ +} + +/** RGB color type. */ +ColorType.RGB = "rgb"; + +/** Gradient color type. */ +ColorType.GRADIENT = "gradient"; + +/** Null color type. */ +ColorType.NONE = "none"; + +/** + * @class RGBColor + * Stores an RGB color with red, green, blue, and alpha values. + * All values are in the range [0.0 to 255.0]. Invalid numeric values are + * converted to numbers within this range. + * + * @param red The red value, in the range [0.0 to 255.0]. + * @param green The green value, in the range [0.0 to 255.0]. + * @param blue The blue value, in the range [0.0 to 255.0]. + * @param alpha The alpha (transparency) value, in the range [0.0 to 255.0]. + * The default, 255.0, means that the color is fully opaque. + * + * @return A new RGBColor object. + */ +function RGBColor(red, green, blue, alpha) +{ + this.red = red; + this.green = green; + this.blue = blue; + this.alpha = alpha; +} + +/** + * @class Direction + * A point value in which the y component is 0 and the x component + * is positive or negative for a right or left direction, + * or the x component is 0 and the y component is positive or negative for + * an up or down direction. + * + * @param x The horizontal component of the point. + * @param y The vertical component of the point. + * + * @return A new \c Direction object. + */ +function Direction(x, y) +{ + this.x = x; + this.y = y; +} + +/** + * @class GradientStop + * Stores gradient stop information. + * + * @param offset The offset of the gradient stop, in the range [0.0 to 1.0]. + * @param rgbColor The color of the gradient at this point, an \c #RGBColor object. + * + * @return GradientStop object. + */ +function GradientStop(offset, rgbColor) +{ + this.offset = offset; + this.rgbColor = rgbColor; +} + +/** + * @class GradientColor + * Stores gradient color information. + * + * @param type The gradient type, must be "linear". + * @param direction A \c #Direction object for the direction of the gradient + (up, down, right, or left). + * @param numStops The number of stops in the gradient. + * @param gradientStopList An array of \c #GradientStop objects. + * + * @return A new \c GradientColor object. + */ +function GradientColor(type, direction, numStops, arrGradientStop) +{ + this.type = type; + this.direction = direction; + this.numStops = numStops; + this.arrGradientStop = arrGradientStop; +} + +/** + * @class UIColor + * Stores color information, including the type, anti-alias level, and specific color + * values in a color object of an appropriate type. + * + * @param type The color type, 1 for "rgb" and 2 for "gradient". + The supplied color object must correspond to this type. + * @param antialiasLevel The anti-alias level constant. + * @param color A \c #RGBColor or \c #GradientColor object containing specific color information. + * + * @return A new \c UIColor object. + */ +function UIColor(type, antialiasLevel, color) +{ + this.type = type; + this.antialiasLevel = antialiasLevel; + this.color = color; +} + +/** + * @class AppSkinInfo + * Stores window-skin properties, such as color and font. All color parameter values are \c #UIColor objects except that systemHighlightColor is \c #RGBColor object. + * + * @param baseFontFamily The base font family of the application. + * @param baseFontSize The base font size of the application. + * @param appBarBackgroundColor The application bar background color. + * @param panelBackgroundColor The background color of the extension panel. + * @param appBarBackgroundColorSRGB The application bar background color, as sRGB. + * @param panelBackgroundColorSRGB The background color of the extension panel, as sRGB. + * @param systemHighlightColor The highlight color of the extension panel, if provided by the host application. Otherwise, the operating-system highlight color. + * + * @return AppSkinInfo object. + */ +function AppSkinInfo(baseFontFamily, baseFontSize, appBarBackgroundColor, panelBackgroundColor, appBarBackgroundColorSRGB, panelBackgroundColorSRGB, systemHighlightColor) +{ + this.baseFontFamily = baseFontFamily; + this.baseFontSize = baseFontSize; + this.appBarBackgroundColor = appBarBackgroundColor; + this.panelBackgroundColor = panelBackgroundColor; + this.appBarBackgroundColorSRGB = appBarBackgroundColorSRGB; + this.panelBackgroundColorSRGB = panelBackgroundColorSRGB; + this.systemHighlightColor = systemHighlightColor; +} + +/** + * @class HostEnvironment + * Stores information about the environment in which the extension is loaded. + * + * @param appName The application's name. + * @param appVersion The application's version. + * @param appLocale The application's current license locale. + * @param appUILocale The application's current UI locale. + * @param appId The application's unique identifier. + * @param isAppOnline True if the application is currently online. + * @param appSkinInfo An \c #AppSkinInfo object containing the application's default color and font styles. + * + * @return A new \c HostEnvironment object. + */ +function HostEnvironment(appName, appVersion, appLocale, appUILocale, appId, isAppOnline, appSkinInfo) +{ + this.appName = appName; + this.appVersion = appVersion; + this.appLocale = appLocale; + this.appUILocale = appUILocale; + this.appId = appId; + this.isAppOnline = isAppOnline; + this.appSkinInfo = appSkinInfo; +} + +/** + * @class HostCapabilities + * Stores information about the host capabilities. + * + * @param EXTENDED_PANEL_MENU True if the application supports panel menu. + * @param EXTENDED_PANEL_ICONS True if the application supports panel icon. + * @param DELEGATE_APE_ENGINE True if the application supports delegated APE engine. + * @param SUPPORT_HTML_EXTENSIONS True if the application supports HTML extensions. + * @param DISABLE_FLASH_EXTENSIONS True if the application disables FLASH extensions. + * + * @return A new \c HostCapabilities object. + */ +function HostCapabilities(EXTENDED_PANEL_MENU, EXTENDED_PANEL_ICONS, DELEGATE_APE_ENGINE, SUPPORT_HTML_EXTENSIONS, DISABLE_FLASH_EXTENSIONS) +{ + this.EXTENDED_PANEL_MENU = EXTENDED_PANEL_MENU; + this.EXTENDED_PANEL_ICONS = EXTENDED_PANEL_ICONS; + this.DELEGATE_APE_ENGINE = DELEGATE_APE_ENGINE; + this.SUPPORT_HTML_EXTENSIONS = SUPPORT_HTML_EXTENSIONS; + this.DISABLE_FLASH_EXTENSIONS = DISABLE_FLASH_EXTENSIONS; // Since 5.0.0 +} + +/** + * @class ApiVersion + * Stores current api version. + * + * Since 4.2.0 + * + * @param major The major version + * @param minor The minor version. + * @param micro The micro version. + * + * @return ApiVersion object. + */ +function ApiVersion(major, minor, micro) +{ + this.major = major; + this.minor = minor; + this.micro = micro; +} + +/** + * @class MenuItemStatus + * Stores flyout menu item status + * + * Since 5.2.0 + * + * @param menuItemLabel The menu item label. + * @param enabled True if user wants to enable the menu item. + * @param checked True if user wants to check the menu item. + * + * @return MenuItemStatus object. + */ +function MenuItemStatus(menuItemLabel, enabled, checked) +{ + this.menuItemLabel = menuItemLabel; + this.enabled = enabled; + this.checked = checked; +} + +/** + * @class ContextMenuItemStatus + * Stores the status of the context menu item. + * + * Since 5.2.0 + * + * @param menuItemID The menu item id. + * @param enabled True if user wants to enable the menu item. + * @param checked True if user wants to check the menu item. + * + * @return MenuItemStatus object. + */ +function ContextMenuItemStatus(menuItemID, enabled, checked) +{ + this.menuItemID = menuItemID; + this.enabled = enabled; + this.checked = checked; +} +//------------------------------ CSInterface ---------------------------------- + +/** + * @class CSInterface + * This is the entry point to the CEP extensibility infrastructure. + * Instantiate this object and use it to: + *
    + *
  • Access information about the host application in which an extension is running
  • + *
  • Launch an extension
  • + *
  • Register interest in event notifications, and dispatch events
  • + *
+ * + * @return A new \c CSInterface object + */ +function CSInterface() +{ +} + +/** + * User can add this event listener to handle native application theme color changes. + * Callback function gives extensions ability to fine-tune their theme color after the + * global theme color has been changed. + * The callback function should be like below: + * + * @example + * // event is a CSEvent object, but user can ignore it. + * function OnAppThemeColorChanged(event) + * { + * // Should get a latest HostEnvironment object from application. + * var skinInfo = JSON.parse(window.__adobe_cep__.getHostEnvironment()).appSkinInfo; + * // Gets the style information such as color info from the skinInfo, + * // and redraw all UI controls of your extension according to the style info. + * } + */ +CSInterface.THEME_COLOR_CHANGED_EVENT = "com.adobe.csxs.events.ThemeColorChanged"; + +/** The host environment data object. */ +CSInterface.prototype.hostEnvironment = window.__adobe_cep__ ? JSON.parse(window.__adobe_cep__.getHostEnvironment()) : null; + +/** Retrieves information about the host environment in which the + * extension is currently running. + * + * @return A \c #HostEnvironment object. + */ +CSInterface.prototype.getHostEnvironment = function() +{ + this.hostEnvironment = JSON.parse(window.__adobe_cep__.getHostEnvironment()); + return this.hostEnvironment; +}; + +/** Loads binary file created which is located at url asynchronously +* +*@param urlName url at which binary file is located. Local files should start with 'file://' +*@param callback Optional. A callback function that returns after binary is loaded + +*@example +* To create JS binary use command ./cep_compiler test.js test.bin +* To load JS binary asyncronously +* var CSLib = new CSInterface(); +* CSLib.loadBinAsync(url, function () { }); +*/ +CSInterface.prototype.loadBinAsync = function(urlName,callback) +{ + try + { + var xhr = new XMLHttpRequest(); + xhr.responseType = 'arraybuffer'; // make response as ArrayBuffer + xhr.open('GET', urlName, true); + xhr.onerror = function () + { + console.log("Unable to load snapshot from given URL"); + return false; + }; + xhr.send(); + xhr.onload = () => { + window.__adobe_cep__.loadSnapshot(xhr.response); + if (typeof callback === "function") + { + callback(); + } + else if(typeof callback !== "undefined") + { + console.log("Provided callback is not a function"); + } + } + } + catch(err) + { + console.log(err); + return false; + } + + return true; +}; + +/** Loads binary file created synchronously +* +*@param pathName the local path at which binary file is located + +*@example +* To create JS binary use command ./cep_compiler test.js test.bin +* To load JS binary syncronously +* var CSLib = new CSInterface(); +* CSLib.loadBinSync(path); +*/ +CSInterface.prototype.loadBinSync = function(pathName) +{ + try + { + var OSVersion = this.getOSInformation(); + if(pathName.startsWith("file://")) + { + if (OSVersion.indexOf("Windows") >= 0) + { + pathName = pathName.replace("file:///", ""); + } + else if (OSVersion.indexOf("Mac") >= 0) + { + pathName = pathName.replace("file://", ""); + } + window.__adobe_cep__.loadSnapshot(pathName); + return true; + } + } + catch(err) + { + console.log(err); + return false; + } + //control should not come here + return false; +}; + +/** Closes this extension. */ +CSInterface.prototype.closeExtension = function() +{ + window.__adobe_cep__.closeExtension(); +}; + +/** + * Retrieves a path for which a constant is defined in the system. + * + * @param pathType The path-type constant defined in \c #SystemPath , + * + * @return The platform-specific system path string. + */ +CSInterface.prototype.getSystemPath = function(pathType) +{ + var path = decodeURI(window.__adobe_cep__.getSystemPath(pathType)); + var OSVersion = this.getOSInformation(); + if (OSVersion.indexOf("Windows") >= 0) + { + path = path.replace("file:///", ""); + } + else if (OSVersion.indexOf("Mac") >= 0) + { + path = path.replace("file://", ""); + } + return path; +}; + +/** + * Evaluates a JavaScript script, which can use the JavaScript DOM + * of the host application. + * + * @param script The JavaScript script. + * @param callback Optional. A callback function that receives the result of execution. + * If execution fails, the callback function receives the error message \c EvalScript_ErrMessage. + */ +CSInterface.prototype.evalScript = function(script, callback) +{ + if(callback === null || callback === undefined) + { + callback = function(result){}; + } + window.__adobe_cep__.evalScript(script, callback); +}; + +/** + * Retrieves the unique identifier of the application. + * in which the extension is currently running. + * + * @return The unique ID string. + */ +CSInterface.prototype.getApplicationID = function() +{ + var appId = this.hostEnvironment.appId; + return appId; +}; + +/** + * Retrieves host capability information for the application + * in which the extension is currently running. + * + * @return A \c #HostCapabilities object. + */ +CSInterface.prototype.getHostCapabilities = function() +{ + var hostCapabilities = JSON.parse(window.__adobe_cep__.getHostCapabilities() ); + return hostCapabilities; +}; + +/** + * Triggers a CEP event programmatically. Yoy can use it to dispatch + * an event of a predefined type, or of a type you have defined. + * + * @param event A \c CSEvent object. + */ +CSInterface.prototype.dispatchEvent = function(event) +{ + if (typeof event.data == "object") + { + event.data = JSON.stringify(event.data); + } + + window.__adobe_cep__.dispatchEvent(event); +}; + +/** + * Registers an interest in a CEP event of a particular type, and + * assigns an event handler. + * The event infrastructure notifies your extension when events of this type occur, + * passing the event object to the registered handler function. + * + * @param type The name of the event type of interest. + * @param listener The JavaScript handler function or method. + * @param obj Optional, the object containing the handler method, if any. + * Default is null. + */ +CSInterface.prototype.addEventListener = function(type, listener, obj) +{ + window.__adobe_cep__.addEventListener(type, listener, obj); +}; + +/** + * Removes a registered event listener. + * + * @param type The name of the event type of interest. + * @param listener The JavaScript handler function or method that was registered. + * @param obj Optional, the object containing the handler method, if any. + * Default is null. + */ +CSInterface.prototype.removeEventListener = function(type, listener, obj) +{ + window.__adobe_cep__.removeEventListener(type, listener, obj); +}; + +/** + * Loads and launches another extension, or activates the extension if it is already loaded. + * + * @param extensionId The extension's unique identifier. + * @param startupParams Not currently used, pass "". + * + * @example + * To launch the extension "help" with ID "HLP" from this extension, call: + * requestOpenExtension("HLP", ""); + * + */ +CSInterface.prototype.requestOpenExtension = function(extensionId, params) +{ + window.__adobe_cep__.requestOpenExtension(extensionId, params); +}; + +/** + * Retrieves the list of extensions currently loaded in the current host application. + * The extension list is initialized once, and remains the same during the lifetime + * of the CEP session. + * + * @param extensionIds Optional, an array of unique identifiers for extensions of interest. + * If omitted, retrieves data for all extensions. + * + * @return Zero or more \c #Extension objects. + */ +CSInterface.prototype.getExtensions = function(extensionIds) +{ + var extensionIdsStr = JSON.stringify(extensionIds); + var extensionsStr = window.__adobe_cep__.getExtensions(extensionIdsStr); + + var extensions = JSON.parse(extensionsStr); + return extensions; +}; + +/** + * Retrieves network-related preferences. + * + * @return A JavaScript object containing network preferences. + */ +CSInterface.prototype.getNetworkPreferences = function() +{ + var result = window.__adobe_cep__.getNetworkPreferences(); + var networkPre = JSON.parse(result); + + return networkPre; +}; + +/** + * Initializes the resource bundle for this extension with property values + * for the current application and locale. + * To support multiple locales, you must define a property file for each locale, + * containing keyed display-string values for that locale. + * See localization documentation for Extension Builder and related products. + * + * Keys can be in the + * form key.value="localized string", for use in HTML text elements. + * For example, in this input element, the localized \c key.value string is displayed + * instead of the empty \c value string: + * + * + * + * @return An object containing the resource bundle information. + */ +CSInterface.prototype.initResourceBundle = function() +{ + var resourceBundle = JSON.parse(window.__adobe_cep__.initResourceBundle()); + var resElms = document.querySelectorAll('[data-locale]'); + for (var n = 0; n < resElms.length; n++) + { + var resEl = resElms[n]; + // Get the resource key from the element. + var resKey = resEl.getAttribute('data-locale'); + if (resKey) + { + // Get all the resources that start with the key. + for (var key in resourceBundle) + { + if (key.indexOf(resKey) === 0) + { + var resValue = resourceBundle[key]; + if (key.length == resKey.length) + { + resEl.innerHTML = resValue; + } + else if ('.' == key.charAt(resKey.length)) + { + var attrKey = key.substring(resKey.length + 1); + resEl[attrKey] = resValue; + } + } + } + } + } + return resourceBundle; +}; + +/** + * Writes installation information to a file. + * + * @return The file path. + */ +CSInterface.prototype.dumpInstallationInfo = function() +{ + return window.__adobe_cep__.dumpInstallationInfo(); +}; + +/** + * Retrieves version information for the current Operating System, + * See http://www.useragentstring.com/pages/Chrome/ for Chrome \c navigator.userAgent values. + * + * @return A string containing the OS version, or "unknown Operation System". + * If user customizes the User Agent by setting CEF command parameter "--user-agent", only + * "Mac OS X" or "Windows" will be returned. + */ +CSInterface.prototype.getOSInformation = function() +{ + var userAgent = navigator.userAgent; + + if ((navigator.platform == "Win32") || (navigator.platform == "Windows")) + { + var winVersion = "Windows"; + var winBit = ""; + if (userAgent.indexOf("Windows") > -1) + { + if (userAgent.indexOf("Windows NT 5.0") > -1) + { + winVersion = "Windows 2000"; + } + else if (userAgent.indexOf("Windows NT 5.1") > -1) + { + winVersion = "Windows XP"; + } + else if (userAgent.indexOf("Windows NT 5.2") > -1) + { + winVersion = "Windows Server 2003"; + } + else if (userAgent.indexOf("Windows NT 6.0") > -1) + { + winVersion = "Windows Vista"; + } + else if (userAgent.indexOf("Windows NT 6.1") > -1) + { + winVersion = "Windows 7"; + } + else if (userAgent.indexOf("Windows NT 6.2") > -1) + { + winVersion = "Windows 8"; + } + else if (userAgent.indexOf("Windows NT 6.3") > -1) + { + winVersion = "Windows 8.1"; + } + else if (userAgent.indexOf("Windows NT 10") > -1) + { + winVersion = "Windows 10"; + } + + if (userAgent.indexOf("WOW64") > -1 || userAgent.indexOf("Win64") > -1) + { + winBit = " 64-bit"; + } + else + { + winBit = " 32-bit"; + } + } + + return winVersion + winBit; + } + else if ((navigator.platform == "MacIntel") || (navigator.platform == "Macintosh")) + { + var result = "Mac OS X"; + + if (userAgent.indexOf("Mac OS X") > -1) + { + result = userAgent.substring(userAgent.indexOf("Mac OS X"), userAgent.indexOf(")")); + result = result.replace(/_/g, "."); + } + + return result; + } + + return "Unknown Operation System"; +}; + +/** + * Opens a page in the default system browser. + * + * Since 4.2.0 + * + * @param url The URL of the page/file to open, or the email address. + * Must use HTTP/HTTPS/file/mailto protocol. For example: + * "http://www.adobe.com" + * "https://github.com" + * "file:///C:/log.txt" + * "mailto:test@adobe.com" + * + * @return One of these error codes:\n + *
    \n + *
  • NO_ERROR - 0
  • \n + *
  • ERR_UNKNOWN - 1
  • \n + *
  • ERR_INVALID_PARAMS - 2
  • \n + *
  • ERR_INVALID_URL - 201
  • \n + *
\n + */ +CSInterface.prototype.openURLInDefaultBrowser = function(url) +{ + return cep.util.openURLInDefaultBrowser(url); +}; + +/** + * Retrieves extension ID. + * + * Since 4.2.0 + * + * @return extension ID. + */ +CSInterface.prototype.getExtensionID = function() +{ + return window.__adobe_cep__.getExtensionId(); +}; + +/** + * Retrieves the scale factor of screen. + * On Windows platform, the value of scale factor might be different from operating system's scale factor, + * since host application may use its self-defined scale factor. + * + * Since 4.2.0 + * + * @return One of the following float number. + *
    \n + *
  • -1.0 when error occurs
  • \n + *
  • 1.0 means normal screen
  • \n + *
  • >1.0 means HiDPI screen
  • \n + *
\n + */ +CSInterface.prototype.getScaleFactor = function() +{ + return window.__adobe_cep__.getScaleFactor(); +}; + +/** + * Retrieves the scale factor of Monitor. + * + * Since 8.5.0 + * + * @return value >= 1.0f + * only available for windows machine + */ + if(navigator.appVersion.toLowerCase().indexOf("windows") >= 0) { + CSInterface.prototype.getMonitorScaleFactor = function() + { + return window.__adobe_cep__.getMonitorScaleFactor(); + }; +} + +/** + * Set a handler to detect any changes of scale factor. This only works on Mac. + * + * Since 4.2.0 + * + * @param handler The function to be called when scale factor is changed. + * + */ +CSInterface.prototype.setScaleFactorChangedHandler = function(handler) +{ + window.__adobe_cep__.setScaleFactorChangedHandler(handler); +}; + +/** + * Retrieves current API version. + * + * Since 4.2.0 + * + * @return ApiVersion object. + * + */ +CSInterface.prototype.getCurrentApiVersion = function() +{ + var apiVersion = JSON.parse(window.__adobe_cep__.getCurrentApiVersion()); + return apiVersion; +}; + +/** + * Set panel flyout menu by an XML. + * + * Since 5.2.0 + * + * Register a callback function for "com.adobe.csxs.events.flyoutMenuClicked" to get notified when a + * menu item is clicked. + * The "data" attribute of event is an object which contains "menuId" and "menuName" attributes. + * + * Register callback functions for "com.adobe.csxs.events.flyoutMenuOpened" and "com.adobe.csxs.events.flyoutMenuClosed" + * respectively to get notified when flyout menu is opened or closed. + * + * @param menu A XML string which describes menu structure. + * An example menu XML: + * + * + * + * + * + * + * + * + * + * + * + * + */ +CSInterface.prototype.setPanelFlyoutMenu = function(menu) +{ + if ("string" != typeof menu) + { + return; + } + + window.__adobe_cep__.invokeSync("setPanelFlyoutMenu", menu); +}; + +/** + * Updates a menu item in the extension window's flyout menu, by setting the enabled + * and selection status. + * + * Since 5.2.0 + * + * @param menuItemLabel The menu item label. + * @param enabled True to enable the item, false to disable it (gray it out). + * @param checked True to select the item, false to deselect it. + * + * @return false when the host application does not support this functionality (HostCapabilities.EXTENDED_PANEL_MENU is false). + * Fails silently if menu label is invalid. + * + * @see HostCapabilities.EXTENDED_PANEL_MENU + */ +CSInterface.prototype.updatePanelMenuItem = function(menuItemLabel, enabled, checked) +{ + var ret = false; + if (this.getHostCapabilities().EXTENDED_PANEL_MENU) + { + var itemStatus = new MenuItemStatus(menuItemLabel, enabled, checked); + ret = window.__adobe_cep__.invokeSync("updatePanelMenuItem", JSON.stringify(itemStatus)); + } + return ret; +}; + + +/** + * Set context menu by XML string. + * + * Since 5.2.0 + * + * There are a number of conventions used to communicate what type of menu item to create and how it should be handled. + * - an item without menu ID or menu name is disabled and is not shown. + * - if the item name is "---" (three hyphens) then it is treated as a separator. The menu ID in this case will always be NULL. + * - Checkable attribute takes precedence over Checked attribute. + * - a PNG icon. For optimal display results please supply a 16 x 16px icon as larger dimensions will increase the size of the menu item. + The Chrome extension contextMenus API was taken as a reference. + https://developer.chrome.com/extensions/contextMenus + * - the items with icons and checkable items cannot coexist on the same menu level. The former take precedences over the latter. + * + * @param menu A XML string which describes menu structure. + * @param callback The callback function which is called when a menu item is clicked. The only parameter is the returned ID of clicked menu item. + * + * @description An example menu XML: + * + * + * + * + * + * + * + * + * + * + * + */ +CSInterface.prototype.setContextMenu = function(menu, callback) +{ + if ("string" != typeof menu) + { + return; + } + + window.__adobe_cep__.invokeAsync("setContextMenu", menu, callback); +}; + +/** + * Set context menu by JSON string. + * + * Since 6.0.0 + * + * There are a number of conventions used to communicate what type of menu item to create and how it should be handled. + * - an item without menu ID or menu name is disabled and is not shown. + * - if the item label is "---" (three hyphens) then it is treated as a separator. The menu ID in this case will always be NULL. + * - Checkable attribute takes precedence over Checked attribute. + * - a PNG icon. For optimal display results please supply a 16 x 16px icon as larger dimensions will increase the size of the menu item. + The Chrome extension contextMenus API was taken as a reference. + * - the items with icons and checkable items cannot coexist on the same menu level. The former take precedences over the latter. + https://developer.chrome.com/extensions/contextMenus + * + * @param menu A JSON string which describes menu structure. + * @param callback The callback function which is called when a menu item is clicked. The only parameter is the returned ID of clicked menu item. + * + * @description An example menu JSON: + * + * { + * "menu": [ + * { + * "id": "menuItemId1", + * "label": "testExample1", + * "enabled": true, + * "checkable": true, + * "checked": false, + * "icon": "./image/small_16X16.png" + * }, + * { + * "id": "menuItemId2", + * "label": "testExample2", + * "menu": [ + * { + * "id": "menuItemId2-1", + * "label": "testExample2-1", + * "menu": [ + * { + * "id": "menuItemId2-1-1", + * "label": "testExample2-1-1", + * "enabled": false, + * "checkable": true, + * "checked": true + * } + * ] + * }, + * { + * "id": "menuItemId2-2", + * "label": "testExample2-2", + * "enabled": true, + * "checkable": true, + * "checked": true + * } + * ] + * }, + * { + * "label": "---" + * }, + * { + * "id": "menuItemId3", + * "label": "testExample3", + * "enabled": false, + * "checkable": true, + * "checked": false + * } + * ] + * } + * + */ +CSInterface.prototype.setContextMenuByJSON = function(menu, callback) +{ + if ("string" != typeof menu) + { + return; + } + + window.__adobe_cep__.invokeAsync("setContextMenuByJSON", menu, callback); +}; + +/** + * Updates a context menu item by setting the enabled and selection status. + * + * Since 5.2.0 + * + * @param menuItemID The menu item ID. + * @param enabled True to enable the item, false to disable it (gray it out). + * @param checked True to select the item, false to deselect it. + */ +CSInterface.prototype.updateContextMenuItem = function(menuItemID, enabled, checked) +{ + var itemStatus = new ContextMenuItemStatus(menuItemID, enabled, checked); + ret = window.__adobe_cep__.invokeSync("updateContextMenuItem", JSON.stringify(itemStatus)); +}; + +/** + * Get the visibility status of an extension window. + * + * Since 6.0.0 + * + * @return true if the extension window is visible; false if the extension window is hidden. + */ +CSInterface.prototype.isWindowVisible = function() +{ + return window.__adobe_cep__.invokeSync("isWindowVisible", ""); +}; + +/** + * Resize extension's content to the specified dimensions. + * 1. Works with modal and modeless extensions in all Adobe products. + * 2. Extension's manifest min/max size constraints apply and take precedence. + * 3. For panel extensions + * 3.1 This works in all Adobe products except: + * * Premiere Pro + * * Prelude + * * After Effects + * 3.2 When the panel is in certain states (especially when being docked), + * it will not change to the desired dimensions even when the + * specified size satisfies min/max constraints. + * + * Since 6.0.0 + * + * @param width The new width + * @param height The new height + */ +CSInterface.prototype.resizeContent = function(width, height) +{ + window.__adobe_cep__.resizeContent(width, height); +}; + +/** + * Register the invalid certificate callback for an extension. + * This callback will be triggered when the extension tries to access the web site that contains the invalid certificate on the main frame. + * But if the extension does not call this function and tries to access the web site containing the invalid certificate, a default error page will be shown. + * + * Since 6.1.0 + * + * @param callback the callback function + */ +CSInterface.prototype.registerInvalidCertificateCallback = function(callback) +{ + return window.__adobe_cep__.registerInvalidCertificateCallback(callback); +}; + +/** + * Register an interest in some key events to prevent them from being sent to the host application. + * + * This function works with modeless extensions and panel extensions. + * Generally all the key events will be sent to the host application for these two extensions if the current focused element + * is not text input or dropdown, + * If you want to intercept some key events and want them to be handled in the extension, please call this function + * in advance to prevent them being sent to the host application. + * + * Since 6.1.0 + * + * @param keyEventsInterest A JSON string describing those key events you are interested in. A null object or + an empty string will lead to removing the interest + * + * This JSON string should be an array, each object has following keys: + * + * keyCode: [Required] represents an OS system dependent virtual key code identifying + * the unmodified value of the pressed key. + * ctrlKey: [optional] a Boolean that indicates if the control key was pressed (true) or not (false) when the event occurred. + * altKey: [optional] a Boolean that indicates if the alt key was pressed (true) or not (false) when the event occurred. + * shiftKey: [optional] a Boolean that indicates if the shift key was pressed (true) or not (false) when the event occurred. + * metaKey: [optional] (Mac Only) a Boolean that indicates if the Meta key was pressed (true) or not (false) when the event occurred. + * On Macintosh keyboards, this is the command key. To detect Windows key on Windows, please use keyCode instead. + * An example JSON string: + * + * [ + * { + * "keyCode": 48 + * }, + * { + * "keyCode": 123, + * "ctrlKey": true + * }, + * { + * "keyCode": 123, + * "ctrlKey": true, + * "metaKey": true + * } + * ] + * + */ +CSInterface.prototype.registerKeyEventsInterest = function(keyEventsInterest) +{ + return window.__adobe_cep__.registerKeyEventsInterest(keyEventsInterest); +}; + +/** + * Set the title of the extension window. + * This function works with modal and modeless extensions in all Adobe products, and panel extensions in Photoshop, InDesign, InCopy, Illustrator, Flash Pro and Dreamweaver. + * + * Since 6.1.0 + * + * @param title The window title. + */ +CSInterface.prototype.setWindowTitle = function(title) +{ + window.__adobe_cep__.invokeSync("setWindowTitle", title); +}; + +/** + * Get the title of the extension window. + * This function works with modal and modeless extensions in all Adobe products, and panel extensions in Photoshop, InDesign, InCopy, Illustrator, Flash Pro and Dreamweaver. + * + * Since 6.1.0 + * + * @return The window title. + */ +CSInterface.prototype.getWindowTitle = function() +{ + return window.__adobe_cep__.invokeSync("getWindowTitle", ""); +}; diff --git a/pype/premiere/extensions/com.pype/lib/Vulcan.js b/pype/premiere/extensions/com.pype/lib/Vulcan.js new file mode 100644 index 00000000000..10db662fd3b --- /dev/null +++ b/pype/premiere/extensions/com.pype/lib/Vulcan.js @@ -0,0 +1,459 @@ +/************************************************************************************************** +* +* ADOBE SYSTEMS INCORPORATED +* Copyright 2013 Adobe Systems Incorporated +* All Rights Reserved. +* +* NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the +* terms of the Adobe license agreement accompanying it. If you have received this file from a +* source other than Adobe, then your use, modification, or distribution of it requires the prior +* written permission of Adobe. +* +**************************************************************************************************/ + +/** Vulcan - v9.2.0 */ + +/** + * @class Vulcan + * + * The singleton instance, VulcanInterface, provides an interface + * to the Vulcan. Allows you to launch CC applications + * and discover information about them. + */ +function Vulcan() +{ +} + +/** + * Gets all available application specifiers on the local machine. + * + * @return The array of all available application specifiers. + */ +Vulcan.prototype.getTargetSpecifiers = function() +{ + var params = {}; + return JSON.parse(window.__adobe_cep__.invokeSync("vulcanGetTargetSpecifiers", JSON.stringify(params))); +}; + +/** + * Launches a CC application on the local machine, if it is not already running. + * + * @param targetSpecifier The application specifier; for example "indesign". + * + * Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version + * and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you + * installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may + * receive wrong result. + * The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". + * + * In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. + * @param focus True to launch in foreground, or false to launch in the background. + * @param cmdLine Optional, command-line parameters to supply to the launch command. + * @return True if the app can be launched, false otherwise. + */ +Vulcan.prototype.launchApp = function(targetSpecifier, focus, cmdLine) +{ + if(!requiredParamsValid(targetSpecifier)) + { + return false; + } + + var params = {}; + params.targetSpecifier = targetSpecifier; + params.focus = focus ? "true" : "false"; + params.cmdLine = requiredParamsValid(cmdLine) ? cmdLine : ""; + + return JSON.parse(window.__adobe_cep__.invokeSync("vulcanLaunchApp", JSON.stringify(params))).result; +}; + +/** + * Checks whether a CC application is running on the local machine. + * + * @param targetSpecifier The application specifier; for example "indesign". + * + * Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version + * and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you + * installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may + * receive wrong result. + * The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". + * + * In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. + * @return True if the app is running, false otherwise. + */ +Vulcan.prototype.isAppRunning = function(targetSpecifier) +{ + if(!requiredParamsValid(targetSpecifier)) + { + return false; + } + + var params = {}; + params.targetSpecifier = targetSpecifier; + + return JSON.parse(window.__adobe_cep__.invokeSync("vulcanIsAppRunning", JSON.stringify(params))).result; +}; + +/** + * Checks whether a CC application is installed on the local machine. + * + * @param targetSpecifier The application specifier; for example "indesign". + * + * Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version + * and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you + * installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may + * receive wrong result. + * The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". + * + * In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. + * @return True if the app is installed, false otherwise. + */ +Vulcan.prototype.isAppInstalled = function(targetSpecifier) +{ + if(!requiredParamsValid(targetSpecifier)) + { + return false; + } + + var params = {}; + params.targetSpecifier = targetSpecifier; + + return JSON.parse(window.__adobe_cep__.invokeSync("vulcanIsAppInstalled", JSON.stringify(params))).result; +}; + +/** + * Retrieves the local install path of a CC application. + * + * @param targetSpecifier The application specifier; for example "indesign". + * + * Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version + * and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you + * installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may + * receive wrong result. + * The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". + * + * In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. + * @return The path string if the application is found, "" otherwise. + */ +Vulcan.prototype.getAppPath = function(targetSpecifier) +{ + if(!requiredParamsValid(targetSpecifier)) + { + return ""; + } + + var params = {}; + params.targetSpecifier = targetSpecifier; + + return JSON.parse(window.__adobe_cep__.invokeSync("vulcanGetAppPath", JSON.stringify(params))).result; +}; + +/** + * Registers a message listener callback function for a Vulcan message. + * + * @param type The message type. + * @param callback The callback function that handles the message. + * Takes one argument, the message object. + * @param obj Optional, the object containing the callback method, if any. + * Default is null. + */ +Vulcan.prototype.addMessageListener = function(type, callback, obj) +{ + if(!requiredParamsValid(type, callback) || !strStartsWith(type, VulcanMessage.TYPE_PREFIX)) + { + return; + } + + var params = {}; + params.type = type; + + window.__adobe_cep__.invokeAsync("vulcanAddMessageListener", JSON.stringify(params), callback, obj); +}; + +/** + * Removes a registered message listener callback function for a Vulcan message. + * + * @param type The message type. + * @param callback The callback function that was registered. + * Takes one argument, the message object. + * @param obj Optional, the object containing the callback method, if any. + * Default is null. + */ +Vulcan.prototype.removeMessageListener = function(type, callback, obj) +{ + if(!requiredParamsValid(type, callback) || !strStartsWith(type, VulcanMessage.TYPE_PREFIX)) + { + return; + } + + var params = {}; + params.type = type; + + window.__adobe_cep__.invokeAsync("vulcanRemoveMessageListener", JSON.stringify(params), callback, obj); +}; + +/** + * Dispatches a Vulcan message. + * + * @param vulcanMessage The message object. + */ +Vulcan.prototype.dispatchMessage = function(vulcanMessage) +{ + if(!requiredParamsValid(vulcanMessage) || !strStartsWith(vulcanMessage.type, VulcanMessage.TYPE_PREFIX)) + { + return; + } + + var params = {}; + var message = new VulcanMessage(vulcanMessage.type); + message.initialize(vulcanMessage); + params.vulcanMessage = message; + + window.__adobe_cep__.invokeSync("vulcanDispatchMessage", JSON.stringify(params)); +}; + +/** + * Retrieves the message payload of a Vulcan message for the registered message listener callback function. + * + * @param vulcanMessage The message object. + * @return A string containing the message payload. + */ +Vulcan.prototype.getPayload = function(vulcanMessage) +{ + if(!requiredParamsValid(vulcanMessage) || !strStartsWith(vulcanMessage.type, VulcanMessage.TYPE_PREFIX)) + { + return null; + } + + var message = new VulcanMessage(vulcanMessage.type); + message.initialize(vulcanMessage); + return message.getPayload(); +}; + +/** + * Gets all available endpoints of the running Vulcan-enabled applications. + * + * Since 7.0.0 + * + * @return The array of all available endpoints. + * An example endpoint string: + * + * PHXS + * 16.1.0 + * + */ +Vulcan.prototype.getEndPoints = function() +{ + var params = {}; + return JSON.parse(window.__adobe_cep__.invokeSync("vulcanGetEndPoints", JSON.stringify(params))); +}; + +/** + * Gets the endpoint for itself. + * + * Since 7.0.0 + * + * @return The endpoint string for itself. + */ +Vulcan.prototype.getSelfEndPoint = function() +{ + var params = {}; + return window.__adobe_cep__.invokeSync("vulcanGetSelfEndPoint", JSON.stringify(params)); +}; + +/** Singleton instance of Vulcan **/ +var VulcanInterface = new Vulcan(); + +//--------------------------------- Vulcan Message ------------------------------ + +/** + * @class VulcanMessage + * Message type for sending messages between host applications. + * A message of this type can be sent to the designated destination + * when appId and appVersion are provided and valid. Otherwise, + * the message is broadcast to all running Vulcan-enabled applications. + * + * To send a message between extensions running within one + * application, use the CSEvent type in CSInterface.js. + * + * @param type The message type. + * @param appId The peer appId. + * @param appVersion The peer appVersion. + * + */ +function VulcanMessage(type, appId, appVersion) +{ + this.type = type; + this.scope = VulcanMessage.SCOPE_SUITE; + this.appId = requiredParamsValid(appId) ? appId : VulcanMessage.DEFAULT_APP_ID; + this.appVersion = requiredParamsValid(appVersion) ? appVersion : VulcanMessage.DEFAULT_APP_VERSION; + this.data = VulcanMessage.DEFAULT_DATA; +} + +VulcanMessage.TYPE_PREFIX = "vulcan.SuiteMessage."; +VulcanMessage.SCOPE_SUITE = "GLOBAL"; +VulcanMessage.DEFAULT_APP_ID = "UNKNOWN"; +VulcanMessage.DEFAULT_APP_VERSION = "UNKNOWN"; +VulcanMessage.DEFAULT_DATA = ""; +VulcanMessage.dataTemplate = "{0}"; +VulcanMessage.payloadTemplate = "{0}"; + +/** + * Initializes this message instance. + * + * @param message A \c message instance to use for initialization. + */ +VulcanMessage.prototype.initialize = function(message) +{ + this.type = message.type; + this.scope = message.scope; + this.appId = message.appId; + this.appVersion = message.appVersion; + this.data = message.data; +}; + +/** + * Retrieves the message data. + * + * @return A data string in XML format. + */ +VulcanMessage.prototype.xmlData = function() +{ + if(this.data === undefined) + { + var str = ""; + str = String.format(VulcanMessage.payloadTemplate, str); + this.data = String.format(VulcanMessage.dataTemplate, str); + } + return this.data; +}; + +/** + * Sets the message payload of this message. + * + * @param payload A string containing the message payload. + */ +VulcanMessage.prototype.setPayload = function(payload) +{ + var str = cep.encoding.convertion.utf8_to_b64(payload); + str = String.format(VulcanMessage.payloadTemplate, str); + this.data = String.format(VulcanMessage.dataTemplate, str); +}; + +/** + * Retrieves the message payload of this message. + * + * @return A string containing the message payload. + */ +VulcanMessage.prototype.getPayload = function() +{ + var str = GetValueByKey(this.data, "payload"); + if(str !== null) + { + return cep.encoding.convertion.b64_to_utf8(str); + } + return null; +}; + +/** + * Converts the properties of this instance to a string. + * + * @return The string version of this instance. + */ +VulcanMessage.prototype.toString = function() +{ + var str = "type=" + this.type; + str += ", scope=" + this.scope; + str += ", appId=" + this.appId; + str += ", appVersion=" + this.appVersion; + str += ", data=" + this.xmlData(); + return str; +}; + +//--------------------------------------- Util -------------------------------- + +/** + * Formats a string based on a template. + * + * @param src The format template. + * + * @return The formatted string + */ +String.format = function(src) +{ + if (arguments.length === 0) + { + return null; + } + + var args = Array.prototype.slice.call(arguments, 1); + return src.replace(/\{(\d+)\}/g, function(m, i){ + return args[i]; + }); +}; + +/** + * Retrieves the content of an XML element. + * + * @param xmlStr The XML string. + * @param key The name of the tag. + * + * @return The content of the tag, or the empty string + * if such tag is not found or the tag has no content. + */ +function GetValueByKey(xmlStr, key) +{ + if(window.DOMParser) + { + var parser = new window.DOMParser(); + try + { + var xmlDoc = parser.parseFromString(xmlStr, "text/xml"); + var node = xmlDoc.getElementsByTagName(key)[0]; + if(node && node.childNodes[0]) + { + return node.childNodes[0].nodeValue; + } + } + catch(e) + { + //log the error + } + } + return ""; +} + +/** + * Reports whether required parameters are valid. + * + * @return True if all required parameters are valid, + * false if any of the required parameters are invalid. + */ +function requiredParamsValid() +{ + for(var i = 0; i < arguments.length; i++) + { + var argument = arguments[i]; + if(argument === undefined || argument === null) + { + return false; + } + } + return true; +} + +/** + * Reports whether a string has a given prefix. + * + * @param str The target string. + * @param prefix The specific prefix string. + * + * @return True if the string has the prefix, false if not. + */ +function strStartsWith(str, prefix) +{ + if(typeof str != "string") + { + return false; + } + return str.indexOf(prefix) === 0; +} diff --git a/pype/premiere/extensions/com.pype.avalon/js/app.js b/pype/premiere/extensions/com.pype/lib/app.js similarity index 51% rename from pype/premiere/extensions/com.pype.avalon/js/app.js rename to pype/premiere/extensions/com.pype/lib/app.js index 059c0ad06ed..84e81ab4c97 100644 --- a/pype/premiere/extensions/com.pype.avalon/js/app.js +++ b/pype/premiere/extensions/com.pype/lib/app.js @@ -1,4 +1,4 @@ // switch between live and local code function onLoaded() { - window.location.href = "http://localhost:4242/ppro/index.html"; + window.location.href = "http://localhost:8021/ppro/index.html"; } diff --git a/pype/premiere/extensions/com.pype/lib/jquery-1.9.1.js b/pype/premiere/extensions/com.pype/lib/jquery-1.9.1.js new file mode 100644 index 00000000000..e2c203fe978 --- /dev/null +++ b/pype/premiere/extensions/com.pype/lib/jquery-1.9.1.js @@ -0,0 +1,9597 @@ +/*! + * jQuery JavaScript Library v1.9.1 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2013-2-4 + */ +(function( window, undefined ) { + +// Can't do this because several apps including ASP.NET trace +// the stack via arguments.caller.callee and Firefox dies if +// you try to trace through "use strict" call chains. (#13335) +// Support: Firefox 18+ +//"use strict"; +var + // The deferred used on DOM ready + readyList, + + // A central reference to the root jQuery(document) + rootjQuery, + + // Support: IE<9 + // For `typeof node.method` instead of `node.method !== undefined` + core_strundefined = typeof undefined, + + // Use the correct document accordingly with window argument (sandbox) + document = window.document, + location = window.location, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // [[Class]] -> type pairs + class2type = {}, + + // List of deleted data cache ids, so we can reuse them + core_deletedIds = [], + + core_version = "1.9.1", + + // Save a reference to some core methods + core_concat = core_deletedIds.concat, + core_push = core_deletedIds.push, + core_slice = core_deletedIds.slice, + core_indexOf = core_deletedIds.indexOf, + core_toString = class2type.toString, + core_hasOwn = class2type.hasOwnProperty, + core_trim = core_version.trim, + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Used for matching numbers + core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, + + // Used for splitting on whitespace + core_rnotwhite = /\S+/g, + + // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE) + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, + rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }, + + // The ready event handler + completed = function( event ) { + + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { + detach(); + jQuery.ready(); + } + }, + // Clean-up method for dom ready events + detach = function() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", completed, false ); + window.removeEventListener( "load", completed, false ); + + } else { + document.detachEvent( "onreadystatechange", completed ); + window.detachEvent( "onload", completed ); + } + }; + +jQuery.fn = jQuery.prototype = { + // The current version of jQuery being used + jquery: core_version, + + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + + // scripts is true for back-compat + jQuery.merge( this, jQuery.parseHTML( + match[1], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return core_slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + ret.context = this.context; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; + }, + + slice: function() { + return this.pushStack( core_slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: core_push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var src, copyIsArray, copy, name, options, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger("ready").off("ready"); + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + if ( obj == null ) { + return String( obj ); + } + return typeof obj === "object" || typeof obj === "function" ? + class2type[ core_toString.call(obj) ] || "object" : + typeof obj; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !core_hasOwn.call(obj, "constructor") && + !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || core_hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + // data: string of html + // context (optional): If specified, the fragment will be created in this context, defaults to document + // keepScripts (optional): If true, will include scripts passed in the html string + parseHTML: function( data, context, keepScripts ) { + if ( !data || typeof data !== "string" ) { + return null; + } + if ( typeof context === "boolean" ) { + keepScripts = context; + context = false; + } + context = context || document; + + var parsed = rsingleTag.exec( data ), + scripts = !keepScripts && []; + + // Single tag + if ( parsed ) { + return [ context.createElement( parsed[1] ) ]; + } + + parsed = jQuery.buildFragment( [ data ], context, scripts ); + if ( scripts ) { + jQuery( scripts ).remove(); + } + return jQuery.merge( [], parsed.childNodes ); + }, + + parseJSON: function( data ) { + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + if ( data === null ) { + return data; + } + + if ( typeof data === "string" ) { + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + if ( data ) { + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + } + } + } + + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + var xml, tmp; + if ( !data || typeof data !== "string" ) { + return null; + } + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && jQuery.trim( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + // args is for internal usage only + each: function( obj, callback, args ) { + var value, + i = 0, + length = obj.length, + isArray = isArraylike( obj ); + + if ( args ) { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } + } + + return obj; + }, + + // Use native String.trim function wherever possible + trim: core_trim && !core_trim.call("\uFEFF\xA0") ? + function( text ) { + return text == null ? + "" : + core_trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArraylike( Object(arr) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + core_push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + var len; + + if ( arr ) { + if ( core_indexOf ) { + return core_indexOf.call( arr, elem, i ); + } + + len = arr.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in arr && arr[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var l = second.length, + i = first.length, + j = 0; + + if ( typeof l === "number" ) { + for ( ; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var retVal, + ret = [], + i = 0, + length = elems.length; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, + i = 0, + length = elems.length, + isArray = isArraylike( elems ), + ret = []; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return core_concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var args, proxy, tmp; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = core_slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + // Multifunctional method to get and set values of a collection + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + length = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < length; i++ ) { + fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; + }, + + now: function() { + return ( new Date() ).getTime(); + } +}); + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + setTimeout( jQuery.ready ); + + // Standards-based browsers support DOMContentLoaded + } else if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed, false ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", completed ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", completed ); + + // If IE and not a frame + // continually check to see if the document is ready + var top = false; + + try { + top = window.frameElement == null && document.documentElement; + } catch(e) {} + + if ( top && top.doScroll ) { + (function doScrollCheck() { + if ( !jQuery.isReady ) { + + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + top.doScroll("left"); + } catch(e) { + return setTimeout( doScrollCheck, 50 ); + } + + // detach all dom ready events + detach(); + + // and execute any waiting functions + jQuery.ready(); + } + })(); + } + } + } + return readyList.promise( obj ); +}; + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +function isArraylike( obj ) { + var length = obj.length, + type = jQuery.type( obj ); + + if ( jQuery.isWindow( obj ) ) { + return false; + } + + if ( obj.nodeType === 1 && length ) { + return true; + } + + return type === "array" || type !== "function" && + ( length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj ); +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache +function createOptions( options ) { + var object = optionsCache[ options ] = {}; + jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) { + object[ flag ] = true; + }); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + ( optionsCache[ options ] || createOptions( options ) ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // First callback to fire (used internally by add and fireWith) + firingStart, + // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = !options.once && [], + // Fire callbacks + fire = function( data ) { + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { + memory = false; // To prevent further calls using add + break; + } + } + firing = false; + if ( list ) { + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } + } else if ( memory ) { + list = []; + } else { + self.disable(); + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + // First, we save the current length + var start = list.length; + (function add( args ) { + jQuery.each( args, function( _, arg ) { + var type = jQuery.type( arg ); + if ( type === "function" ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && type !== "string" ) { + // Inspect recursively + add( arg ); + } + }); + })( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } + } + }); + } + return this; + }, + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + if ( list && ( !fired || stack ) ) { + if ( firing ) { + stack.push( args ); + } else { + fire( args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; +jQuery.extend({ + + Deferred: function( func ) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], + [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], + [ "notify", "progress", jQuery.Callbacks("memory") ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred(function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var action = tuple[ 0 ], + fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[1] ](function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .done( newDefer.resolve ) + .fail( newDefer.reject ) + .progress( newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); + } + }); + }); + fns = null; + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[1] ] = list.add; + + // Handle state + if ( stateString ) { + list.add(function() { + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] + deferred[ tuple[0] ] = function() { + deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); + return this; + }; + deferred[ tuple[0] + "With" ] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = core_slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; + if( values === progressValues ) { + deferred.notifyWith( contexts, values ); + } else if ( !( --remaining ) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ) + .progress( updateFunc( i, progressContexts, progressValues ) ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +}); +jQuery.support = (function() { + + var support, all, a, + input, select, fragment, + opt, eventName, isSupported, i, + div = document.createElement("div"); + + // Setup + div.setAttribute( "className", "t" ); + div.innerHTML = "
a"; + + // Support tests won't run in some limited or non-browser environments + all = div.getElementsByTagName("*"); + a = div.getElementsByTagName("a")[ 0 ]; + if ( !all || !a || !all.length ) { + return {}; + } + + // First batch of tests + select = document.createElement("select"); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName("input")[ 0 ]; + + a.style.cssText = "top:1px;float:left;opacity:.5"; + support = { + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: div.firstChild.nodeType === 3, + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: a.getAttribute("href") === "/a", + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.5/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere) + checkOn: !!input.value, + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Tests for enctype support on a form (#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + + // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode + boxModel: document.compatMode === "CSS1Compat", + + // Will be defined later + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true, + boxSizingReliable: true, + pixelPosition: false + }; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Support: IE<9 + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + // Check if we can trust getAttribute("value") + input = document.createElement("input"); + input.setAttribute( "value", "" ); + support.input = input.getAttribute( "value" ) === ""; + + // Check if an input maintains its value after becoming a radio + input.value = "t"; + input.setAttribute( "type", "radio" ); + support.radioValue = input.value === "t"; + + // #11217 - WebKit loses check when the name is after the checked attribute + input.setAttribute( "checked", "t" ); + input.setAttribute( "name", "t" ); + + fragment = document.createDocumentFragment(); + fragment.appendChild( input ); + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE<9 + // Opera does not clone events (and typeof div.attachEvent === undefined). + // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() + if ( div.attachEvent ) { + div.attachEvent( "onclick", function() { + support.noCloneEvent = false; + }); + + div.cloneNode( true ).click(); + } + + // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event) + // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php + for ( i in { submit: true, change: true, focusin: true }) { + div.setAttribute( eventName = "on" + i, "t" ); + + support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false; + } + + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + // Run tests that need a body at doc ready + jQuery(function() { + var container, marginDiv, tds, + divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;", + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + container = document.createElement("div"); + container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px"; + + body.appendChild( container ).appendChild( div ); + + // Support: IE8 + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + div.innerHTML = "
t
"; + tds = div.getElementsByTagName("td"); + tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Support: IE8 + // Check if empty table cells still have offsetWidth/Height + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Check box-sizing and margin behavior + div.innerHTML = ""; + div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; + support.boxSizing = ( div.offsetWidth === 4 ); + support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); + + // Use window.getComputedStyle because jsdom on node.js will break without it. + if ( window.getComputedStyle ) { + support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; + support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. (#3333) + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + marginDiv = div.appendChild( document.createElement("div") ); + marginDiv.style.cssText = div.style.cssText = divReset; + marginDiv.style.marginRight = marginDiv.style.width = "0"; + div.style.width = "1px"; + + support.reliableMarginRight = + !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); + } + + if ( typeof div.style.zoom !== core_strundefined ) { + // Support: IE<8 + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + div.innerHTML = ""; + div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); + + // Support: IE6 + // Check if elements with layout shrink-wrap their children + div.style.display = "block"; + div.innerHTML = "
"; + div.firstChild.style.width = "5px"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); + + if ( support.inlineBlockNeedsLayout ) { + // Prevent IE 6 from affecting layout for positioned elements #11048 + // Prevent IE from shrinking the body in IE 7 mode #12869 + // Support: IE<8 + body.style.zoom = 1; + } + } + + body.removeChild( container ); + + // Null elements to avoid leaks in IE + container = div = tds = marginDiv = null; + }); + + // Null elements to avoid leaks in IE + all = select = fragment = opt = a = input = null; + + return support; +})(); + +var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, + rmultiDash = /([A-Z])/g; + +function internalData( elem, name, data, pvt /* Internal Use Only */ ){ + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; +} + +function internalRemoveData( elem, name, pvt ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var i, l, thisCache, + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split(" "); + } + } + } else { + // If "name" is an array of keys... + // When data is initially created, via ("key", "val") signature, + // keys will be converted to camelCase. + // Since there is no way to tell _how_ a key was added, remove + // both plain key and camelCase key. #12786 + // This will only penalize the array argument path. + name = name.concat( jQuery.map( name, jQuery.camelCase ) ); + } + + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject( cache[ id ] ) ) { + return; + } + } + + // Destroy the cache + if ( isNode ) { + jQuery.cleanData( [ elem ], true ); + + // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) + } else if ( jQuery.support.deleteExpando || cache != cache.window ) { + delete cache[ id ]; + + // When all else fails, null + } else { + cache[ id ] = null; + } +} + +jQuery.extend({ + cache: {}, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data ) { + return internalData( elem, name, data ); + }, + + removeData: function( elem, name ) { + return internalRemoveData( elem, name ); + }, + + // For internal use only. + _data: function( elem, name, data ) { + return internalData( elem, name, data, true ); + }, + + _removeData: function( elem, name ) { + return internalRemoveData( elem, name, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + // Do not set data on non-element because it will not be cleared (#8335). + if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) { + return false; + } + + var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; + + // nodes accept data unless otherwise specified; rejection can be conditional + return !noData || noData !== true && elem.getAttribute("classid") === noData; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var attrs, name, + elem = this[0], + i = 0, + data = null; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attrs = elem.attributes; + for ( ; i < attrs.length; i++ ) { + name = attrs[i].name; + + if ( !name.indexOf( "data-" ) ) { + name = jQuery.camelCase( name.slice(5) ); + + dataAttr( elem, name, data[ name ] ); + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + return jQuery.access( this, function( value ) { + + if ( value === undefined ) { + // Try to fetch any internally stored data first + return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null; + } + + this.each(function() { + jQuery.data( this, key, value ); + }); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + var name; + for ( name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} +jQuery.extend({ + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray(data) ) { + queue = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + hooks.cur = fn; + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return jQuery._data( elem, key ) || jQuery._data( elem, key, { + empty: jQuery.Callbacks("once memory").add(function() { + jQuery._removeData( elem, type + "queue" ); + jQuery._removeData( elem, key ); + }) + }); + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while( i-- ) { + tmp = jQuery._data( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +}); +var nodeHook, boolHook, + rclass = /[\t\r\n]/g, + rreturn = /\r/g, + rfocusable = /^(?:input|select|textarea|button|object)$/i, + rclickable = /^(?:a|area)$/i, + rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i, + ruseDefault = /^(?:checked|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + getSetInput = jQuery.support.input; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classes, elem, cur, clazz, j, + i = 0, + len = this.length, + proceed = typeof value === "string" && value; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call( this, j, this.className ) ); + }); + } + + if ( proceed ) { + // The disjunction here is for better compressibility (see removeClass) + classes = ( value || "" ).match( core_rnotwhite ) || []; + + for ( ; i < len; i++ ) { + elem = this[ i ]; + cur = elem.nodeType === 1 && ( elem.className ? + ( " " + elem.className + " " ).replace( rclass, " " ) : + " " + ); + + if ( cur ) { + j = 0; + while ( (clazz = classes[j++]) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + elem.className = jQuery.trim( cur ); + + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, clazz, j, + i = 0, + len = this.length, + proceed = arguments.length === 0 || typeof value === "string" && value; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call( this, j, this.className ) ); + }); + } + if ( proceed ) { + classes = ( value || "" ).match( core_rnotwhite ) || []; + + for ( ; i < len; i++ ) { + elem = this[ i ]; + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( elem.className ? + ( " " + elem.className + " " ).replace( rclass, " " ) : + "" + ); + + if ( cur ) { + j = 0; + while ( (clazz = classes[j++]) ) { + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) >= 0 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + elem.className = value ? jQuery.trim( cur ) : ""; + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.match( core_rnotwhite ) || []; + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space separated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + // Toggle whole class name + } else if ( type === core_strundefined || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // If the element has a class name or if we're passed "false", + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var ret, hooks, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var val, + self = jQuery(this); + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, option, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one" || index < 0, + values = one ? null : [], + max = one ? index + 1 : options.length, + i = index < 0 ? + max : + one ? index : 0; + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // oldIE doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + // Don't return options that are disabled or in a disabled optgroup + ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && + ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attr: function( elem, name, value ) { + var hooks, notxml, ret, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === core_strundefined ) { + return jQuery.prop( elem, name, value ); + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + + } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, value + "" ); + return value; + } + + } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + // In IE9+, Flash objects don't have .getAttribute (#12945) + // Support: IE9+ + if ( typeof elem.getAttribute !== core_strundefined ) { + ret = elem.getAttribute( name ); + } + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var name, propName, + i = 0, + attrNames = value && value.match( core_rnotwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( (name = attrNames[i++]) ) { + propName = jQuery.propFix[ name ] || name; + + // Boolean attributes get special treatment (#10870) + if ( rboolean.test( name ) ) { + // Set corresponding property to false for boolean attributes + // Also clear defaultChecked/defaultSelected (if appropriate) for IE<8 + if ( !getSetAttribute && ruseDefault.test( name ) ) { + elem[ jQuery.camelCase( "default-" + name ) ] = + elem[ propName ] = false; + } else { + elem[ propName ] = false; + } + + // See #9699 for explanation of this approach (setting first, then removal) + } else { + jQuery.attr( elem, name, "" ); + } + + elem.removeAttribute( getSetAttribute ? name : propName ); + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to default in case type is set after value during creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + var + // Use .prop to determine if this attribute is understood as boolean + prop = jQuery.prop( elem, name ), + + // Fetch it accordingly + attr = typeof prop === "boolean" && elem.getAttribute( name ), + detail = typeof prop === "boolean" ? + + getSetInput && getSetAttribute ? + attr != null : + // oldIE fabricates an empty string for missing boolean attributes + // and conflates checked/selected into attroperties + ruseDefault.test( name ) ? + elem[ jQuery.camelCase( "default-" + name ) ] : + !!attr : + + // fetch an attribute node for properties not recognized as boolean + elem.getAttributeNode( name ); + + return detail && detail.value !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { + // IE<8 needs the *property* name + elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name ); + + // Use defaultChecked and defaultSelected for oldIE + } else { + elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true; + } + + return name; + } +}; + +// fix oldIE value attroperty +if ( !getSetInput || !getSetAttribute ) { + jQuery.attrHooks.value = { + get: function( elem, name ) { + var ret = elem.getAttributeNode( name ); + return jQuery.nodeName( elem, "input" ) ? + + // Ignore the value *property* by using defaultValue + elem.defaultValue : + + ret && ret.specified ? ret.value : undefined; + }, + set: function( elem, value, name ) { + if ( jQuery.nodeName( elem, "input" ) ) { + // Does not return so that setAttribute is also used + elem.defaultValue = value; + } else { + // Use nodeHook if defined (#1954); otherwise setAttribute is fine + return nodeHook && nodeHook.set( elem, value, name ); + } + } + }; +} + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret = elem.getAttributeNode( name ); + return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ? + ret.value : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + elem.setAttributeNode( + (ret = elem.ownerDocument.createAttribute( name )) + ); + } + + ret.value = value += ""; + + // Break association with cloned elements by also using setAttribute (#9646) + return name === "value" || value === elem.getAttribute( name ) ? + value : + undefined; + } + }; + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + nodeHook.set( elem, value === "" ? false : value, name ); + } + }; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); +} + + +// Some attributes require a special call on IE +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret == null ? undefined : ret; + } + }); + }); + + // href/src property should get the full normalized URL (#10299/#12915) + jQuery.each([ "href", "src" ], function( i, name ) { + jQuery.propHooks[ name ] = { + get: function( elem ) { + return elem.getAttribute( name, 4 ); + } + }; + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Note: IE uppercases css property names, but if we were to .toLowerCase() + // .cssText, that would destroy case senstitivity in URL's, like in "background" + return elem.style.cssText || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = value + "" ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); +var rformElems = /^(?:input|select|textarea)$/i, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + var tmp, events, t, handleObjIn, + special, eventHandle, handleObj, + handlers, type, namespaces, origType, + elemData = jQuery._data( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !(events = elemData.events) ) { + events = elemData.events = {}; + } + if ( !(eventHandle = elemData.handle) ) { + eventHandle = elemData.handle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = ( types || "" ).match( core_rnotwhite ) || [""]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !(handlers = events[ type ]) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + var j, handleObj, tmp, + origCount, t, events, + special, handlers, type, + namespaces, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( core_rnotwhite ) || [""]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery._removeData( elem, "events" ); + } + }, + + trigger: function( event, data, elem, onlyHandlers ) { + var handle, ontype, cur, + bubbleType, special, tmp, i, + eventPath = [ elem || document ], + type = core_hasOwn.call( event, "type" ) ? event.type : event, + namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf(":") < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + event.isTrigger = true; + event.namespace = namespaces.join("."); + event.namespace_re = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === (elem.ownerDocument || document) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + try { + elem[ type ](); + } catch ( e ) { + // IE<9 dies on focus/blur to hidden element (#1486,#12518) + // only reproducible on winXP IE8 native, not IE9 in IE8 mode + } + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, ret, handleObj, matched, j, + handlerQueue = [], + args = core_slice.call( arguments ), + handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( (event.result = ret) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var sel, handleObj, matches, i, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { + + for ( ; cur != this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, handlers: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); + } + + return handlerQueue; + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: IE<9 + // Fix target property (#1925) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Support: Chrome 23+, Safari? + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Support: IE<9 + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) + event.metaKey = !!event.metaKey; + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var body, eventDoc, doc, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { + this.click(); + return false; + } + } + }, + focus: { + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== document.activeElement && this.focus ) { + try { + this.focus(); + return false; + } catch ( e ) { + // Support: IE<9 + // If we error on focus to hidden element (#1486, #12518), + // let .trigger() run the handlers + } + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === document.activeElement && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + + beforeunload: { + postDispatch: function( event ) { + + // Even when returnValue equals to undefined Firefox will still show alert + if ( event.result !== undefined ) { + event.originalEvent.returnValue = event.result; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 + // detachEvent needed property on element, by name of that event, to properly expose it to GC + if ( typeof elem[ name ] === core_strundefined ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + if ( !e ) { + return; + } + + // If preventDefault exists, run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // Support: IE + // Otherwise set the returnValue property of the original event to false + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + if ( !e ) { + return; + } + // If stopPropagation exists, run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + + // Support: IE + // Set the cancelBubble property of the original event to true + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + } +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !jQuery._data( form, "submitBubbles" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + jQuery._data( form, "submitBubbles", true ); + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !jQuery.support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + } + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event, true ); + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + jQuery._data( elem, "changeBubbles", true ); + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var type, origFn; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + var elem = this[0]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +}); +/*! + * Sizzle CSS Selector Engine + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license + * http://sizzlejs.com/ + */ +(function( window, undefined ) { + +var i, + cachedruns, + Expr, + getText, + isXML, + compile, + hasDuplicate, + outermostContext, + + // Local document vars + setDocument, + document, + docElem, + documentIsXML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + sortOrder, + + // Instance-specific data + expando = "sizzle" + -(new Date()), + preferredDoc = window.document, + support = {}, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + + // General-purpose constants + strundefined = typeof undefined, + MAX_NEGATIVE = 1 << 31, + + // Array methods + arr = [], + pop = arr.pop, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf if we can't use a native one + indexOf = arr.indexOf || function( elem ) { + var i = 0, + len = this.length; + for ( ; i < len; i++ ) { + if ( this[i] === elem ) { + return i; + } + } + return -1; + }, + + + // Regular expressions + + // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + // http://www.w3.org/TR/css3-syntax/#characters + characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + + // Loosely modeled on CSS identifier characters + // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors + // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = characterEncoding.replace( "w", "w#" ), + + // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors + operators = "([*^$|!~]?=)", + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + + "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", + + // Prefer arguments quoted, + // then not containing pseudos/brackets, + // then attribute selectors/non-parenthetical expressions, + // then anything else + // These preferences are here to reduce the number of selectors + // needing tokenize in the PSEUDO preFilter + pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ), + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + characterEncoding + ")" ), + "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), + "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), + "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rsibling = /[\x20\t\r\n\f]*[+~]/, + + rnative = /^[^{]+\{\s*\[native code/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rescape = /'|\\/g, + rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, + + // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g, + funescape = function( _, escaped ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + return high !== high ? + escaped : + // BMP codepoint + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }; + +// Use a stripped-down slice if we can't use a native one +try { + slice.call( preferredDoc.documentElement.childNodes, 0 )[0].nodeType; +} catch ( e ) { + slice = function( i ) { + var elem, + results = []; + while ( (elem = this[i++]) ) { + results.push( elem ); + } + return results; + }; +} + +/** + * For feature detection + * @param {Function} fn The function to test for native support + */ +function isNative( fn ) { + return rnative.test( fn + "" ); +} + +/** + * Create key-value caches of limited size + * @returns {Function(string, Object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var cache, + keys = []; + + return (cache = function( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key += " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key ] = value); + }); +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created div and expects a boolean result + */ +function assert( fn ) { + var div = document.createElement("div"); + + try { + return fn( div ); + } catch (e) { + return false; + } finally { + // release memory in IE + div = null; + } +} + +function Sizzle( selector, context, results, seed ) { + var match, elem, m, nodeType, + // QSA vars + i, groups, old, nid, newContext, newSelector; + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + + context = context || document; + results = results || []; + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { + return []; + } + + if ( !documentIsXML && !seed ) { + + // Shortcuts + if ( (match = rquickExpr.exec( selector )) ) { + // Speed-up: Sizzle("#ID") + if ( (m = match[1]) ) { + if ( nodeType === 9 ) { + elem = context.getElementById( m ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE, Opera, and Webkit return items + // by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + } else { + // Context is not a document + if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && + contains( context, elem ) && elem.id === m ) { + results.push( elem ); + return results; + } + } + + // Speed-up: Sizzle("TAG") + } else if ( match[2] ) { + push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); + return results; + + // Speed-up: Sizzle(".CLASS") + } else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) { + push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); + return results; + } + } + + // QSA path + if ( support.qsa && !rbuggyQSA.test(selector) ) { + old = true; + nid = expando; + newContext = context; + newSelector = nodeType === 9 && selector; + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + groups = tokenize( selector ); + + if ( (old = context.getAttribute("id")) ) { + nid = old.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", nid ); + } + nid = "[id='" + nid + "'] "; + + i = groups.length; + while ( i-- ) { + groups[i] = nid + toSelector( groups[i] ); + } + newContext = rsibling.test( selector ) && context.parentNode || context; + newSelector = groups.join(","); + } + + if ( newSelector ) { + try { + push.apply( results, slice.call( newContext.querySelectorAll( + newSelector + ), 0 ) ); + return results; + } catch(qsaError) { + } finally { + if ( !old ) { + context.removeAttribute("id"); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Detect xml + * @param {Element|Object} elem An element or a document + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var doc = node ? node.ownerDocument || node : preferredDoc; + + // If no document and documentElement is available, return + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Set our document + document = doc; + docElem = doc.documentElement; + + // Support tests + documentIsXML = isXML( doc ); + + // Check if getElementsByTagName("*") returns only elements + support.tagNameNoComments = assert(function( div ) { + div.appendChild( doc.createComment("") ); + return !div.getElementsByTagName("*").length; + }); + + // Check if attributes should be retrieved by attribute nodes + support.attributes = assert(function( div ) { + div.innerHTML = ""; + var type = typeof div.lastChild.getAttribute("multiple"); + // IE8 returns a string for some attributes even when not present + return type !== "boolean" && type !== "string"; + }); + + // Check if getElementsByClassName can be trusted + support.getByClassName = assert(function( div ) { + // Opera can't find a second classname (in 9.6) + div.innerHTML = ""; + if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) { + return false; + } + + // Safari 3.2 caches class attributes and doesn't catch changes + div.lastChild.className = "e"; + return div.getElementsByClassName("e").length === 2; + }); + + // Check if getElementById returns elements by name + // Check if getElementsByName privileges form controls or returns elements by ID + support.getByName = assert(function( div ) { + // Inject content + div.id = expando + 0; + div.innerHTML = "
"; + docElem.insertBefore( div, docElem.firstChild ); + + // Test + var pass = doc.getElementsByName && + // buggy browsers will return fewer than the correct 2 + doc.getElementsByName( expando ).length === 2 + + // buggy browsers will return more than the correct 0 + doc.getElementsByName( expando + 0 ).length; + support.getIdNotName = !doc.getElementById( expando ); + + // Cleanup + docElem.removeChild( div ); + + return pass; + }); + + // IE6/7 return modified attributes + Expr.attrHandle = assert(function( div ) { + div.innerHTML = ""; + return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && + div.firstChild.getAttribute("href") === "#"; + }) ? + {} : + { + "href": function( elem ) { + return elem.getAttribute( "href", 2 ); + }, + "type": function( elem ) { + return elem.getAttribute("type"); + } + }; + + // ID find and filter + if ( support.getIdNotName ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== strundefined && !documentIsXML ) { + var m = context.getElementById( id ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== strundefined && !documentIsXML ) { + var m = context.getElementById( id ); + + return m ? + m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? + [m] : + undefined : + []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.tagNameNoComments ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== strundefined ) { + return context.getElementsByTagName( tag ); + } + } : + function( tag, context ) { + var elem, + tmp = [], + i = 0, + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Name + Expr.find["NAME"] = support.getByName && function( tag, context ) { + if ( typeof context.getElementsByName !== strundefined ) { + return context.getElementsByName( name ); + } + }; + + // Class + Expr.find["CLASS"] = support.getByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) { + return context.getElementsByClassName( className ); + } + }; + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21), + // no need to also add to buggyMatches since matches checks buggyQSA + // A support test would require too much code (would include document ready) + rbuggyQSA = [ ":focus" ]; + + if ( (support.qsa = isNative(doc.querySelectorAll)) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explictly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + div.innerHTML = ""; + + // IE8 - Some boolean attributes are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + }); + + assert(function( div ) { + + // Opera 10-12/IE8 - ^= $= *= and empty values + // Should not select anything + div.innerHTML = ""; + if ( div.querySelectorAll("[i^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + div.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector || + docElem.mozMatchesSelector || + docElem.webkitMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( div, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = new RegExp( rbuggyMatches.join("|") ); + + // Element contains another + // Purposefully does not implement inclusive descendent + // As in, an element does not contain itself + contains = isNative(docElem.contains) || docElem.compareDocumentPosition ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + // Document order sorting + sortOrder = docElem.compareDocumentPosition ? + function( a, b ) { + var compare; + + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) { + if ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) { + if ( a === doc || contains( preferredDoc, a ) ) { + return -1; + } + if ( b === doc || contains( preferredDoc, b ) ) { + return 1; + } + return 0; + } + return compare & 4 ? -1 : 1; + } + + return a.compareDocumentPosition ? -1 : 1; + } : + function( a, b ) { + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Parentless nodes are either documents or disconnected + } else if ( !aup || !bup ) { + return a === doc ? -1 : + b === doc ? 1 : + aup ? -1 : + bup ? 1 : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + // Always assume the presence of duplicates if sort doesn't + // pass them to our comparison function (as in Google Chrome). + hasDuplicate = false; + [0, 0].sort( sortOrder ); + support.detectDuplicates = hasDuplicate; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + // rbuggyQSA always contains :focus, so no need for an existence check + if ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) { + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch(e) {} + } + + return Sizzle( expr, document, null, [elem] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + var val; + + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + if ( !documentIsXML ) { + name = name.toLowerCase(); + } + if ( (val = Expr.attrHandle[ name ]) ) { + return val( elem ); + } + if ( documentIsXML || support.attributes ) { + return elem.getAttribute( name ); + } + return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ? + name : + val && val.specified ? val.value : null; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +// Document sorting and removing duplicates +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + i = 1, + j = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( ; (elem = results[i]); i++ ) { + if ( elem === results[ i - 1 ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + return results; +}; + +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE ); + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +// Returns a function to use in pseudos for input types +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +// Returns a function to use in pseudos for buttons +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +// Returns a function to use in pseudos for positionals +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + for ( ; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (see #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[5] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[4] ) { + match[2] = match[4]; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeName ) { + if ( nodeName === "*" ) { + return function() { return true; }; + } + + nodeName = nodeName.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, outerCache, node, diff, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + // Seek `elem` from a previously-cached index + outerCache = parent[ expando ] || (parent[ expando ] = {}); + cache = outerCache[ type ] || []; + nodeIndex = cache[0] === dirruns && cache[1]; + diff = cache[0] === dirruns && cache[2]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + outerCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + // Use previously-cached element index if available + } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { + diff = cache[1]; + + // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) + } else { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { + // Cache the index of each encountered element + if ( useCache ) { + (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifider + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsXML ? + elem.getAttribute("xml:lang") || elem.getAttribute("lang") : + elem.lang) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), + // not comment, processing instructions, or others + // Thanks to Diego Perini for the nodeName shortcut + // Greater than "@" means alpha characters (specifically not starting with "#" or "?") + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +function tokenize( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( tokens = [] ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push( { + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +} + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var data, cache, outerCache, + dirkey = dirruns + " " + doneName; + + // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) { + if ( (data = cache[1]) === true || data === cachedruns ) { + return data === true; + } + } else { + cache = outerCache[ dir ] = [ dirkey ]; + cache[1] = matcher( elem, context, xml ) || cachedruns; + if ( cache[1] === true ) { + return true; + } + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + // A counter to specify which element is currently being matched + var matcherCachedRuns = 0, + bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, expandContext ) { + var elem, j, matcher, + setMatched = [], + matchedCount = 0, + i = "0", + unmatched = seed && [], + outermost = expandContext != null, + contextBackup = outermostContext, + // We must always have either seed elements or context + elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1); + + if ( outermost ) { + outermostContext = context !== document && context; + cachedruns = matcherCachedRuns; + } + + // Add elements passing elementMatchers directly to results + // Keep `i` a string if there are no elements so `matchedCount` will be "00" below + for ( ; (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + cachedruns = ++matcherCachedRuns; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // Apply set filters to unmatched elements + matchedCount += i; + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !group ) { + group = tokenize( selector ); + } + i = group.length; + while ( i-- ) { + cached = matcherFromTokens( group[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + } + return cached; +}; + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function select( selector, context, results, seed ) { + var i, tokens, token, type, find, + match = tokenize( selector ); + + if ( !seed ) { + // Try to minimize operations if there is only one group + if ( match.length === 1 ) { + + // Take a shortcut and set the context if the root selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && !documentIsXML && + Expr.relative[ tokens[1].type ] ) { + + context = Expr.find["ID"]( token.matches[0].replace( runescape, funescape ), context )[0]; + if ( !context ) { + return results; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && context.parentNode || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, slice.call( seed, 0 ) ); + return results; + } + + break; + } + } + } + } + } + + // Compile and execute a filtering function + // Provide `match` to avoid retokenization if we modified the selector above + compile( selector, match )( + seed, + context, + documentIsXML, + results, + rsibling.test( selector ) + ); + return results; +} + +// Deprecated +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Easy API for creating new setFilters +function setFilters() {} +Expr.filters = setFilters.prototype = Expr.pseudos; +Expr.setFilters = new setFilters(); + +// Initialize with the default document +setDocument(); + +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.pseudos; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})( window ); +var runtil = /Until$/, + rparentsprev = /^(?:parents|prev(?:Until|All))/, + isSimple = /^.[^:#\[\.,]*$/, + rneedsContext = jQuery.expr.match.needsContext, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var i, ret, self, + len = this.length; + + if ( typeof selector !== "string" ) { + self = this; + return this.pushStack( jQuery( selector ).filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }) ); + } + + ret = []; + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, this[ i ], ret ); + } + + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = ( this.selector ? this.selector + " " : "" ) + selector; + return ret; + }, + + has: function( target ) { + var i, + targets = jQuery( target, this ), + len = targets.length; + + return this.filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false) ); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true) ); + }, + + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + rneedsContext.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + ret = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + cur = this[i]; + + while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + } + cur = cur.parentNode; + } + } + + return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( jQuery.unique(all) ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter(selector) + ); + } +}); + +jQuery.fn.andSelf = jQuery.fn.addBack; + +function sibling( cur, dir ) { + do { + cur = cur[ dir ]; + } while ( cur && cur.nodeType !== 1 ); + + return cur; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( this.length > 1 && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem ) { + return ( elem === qualifier ) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; + }); +} +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rtbody = /\s*$/g, + + // We have to close these tags to support XHTML (#13200) + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
", "
" ], + area: [ 1, "", "" ], + param: [ 1, "", "" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + col: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, + // unless wrapped in a div with non-breaking characters in front of it. + _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
", "
" ] + }, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement("div") ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +jQuery.fn.extend({ + text: function( value ) { + return jQuery.access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); + }, null, value, arguments.length ); + }, + + wrapAll: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapAll( html.call(this, i) ); + }); + } + + if ( this[0] ) { + // The elements to wrap the target around + var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); + + if ( this[0].parentNode ) { + wrap.insertBefore( this[0] ); + } + + wrap.map(function() { + var elem = this; + + while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { + elem = elem.firstChild; + } + + return elem; + }).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapInner( html.call(this, i) ); + }); + } + + return this.each(function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + }); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each(function(i) { + jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); + }); + }, + + unwrap: function() { + return this.parent().each(function() { + if ( !jQuery.nodeName( this, "body" ) ) { + jQuery( this ).replaceWith( this.childNodes ); + } + }).end(); + }, + + append: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.insertBefore( elem, this.firstChild ); + } + }); + }, + + before: function() { + return this.domManip( arguments, false, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + }); + }, + + after: function() { + return this.domManip( arguments, false, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + }); + }, + + // keepData is for internal use only--do not document + remove: function( selector, keepData ) { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) { + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem ) ); + } + + if ( elem.parentNode ) { + if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { + setGlobalEval( getAll( elem, "script" ) ); + } + elem.parentNode.removeChild( elem ); + } + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + + // If this is a select, ensure that it displays empty (#12336) + // Support: IE<9 + if ( elem.options && jQuery.nodeName( elem, "select" ) ) { + elem.options.length = 0; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function () { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return jQuery.access( this, function( value ) { + var elem = this[0] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for (; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + elem = this[i] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function( value ) { + var isFunc = jQuery.isFunction( value ); + + // Make sure that the elements are removed from the DOM before they are inserted + // this can help fix replacing a parent with child elements + if ( !isFunc && typeof value !== "string" ) { + value = jQuery( value ).not( this ).detach(); + } + + return this.domManip( [ value ], true, function( elem ) { + var next = this.nextSibling, + parent = this.parentNode; + + if ( parent ) { + jQuery( this ).remove(); + parent.insertBefore( elem, next ); + } + }); + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, table, callback ) { + + // Flatten any nested arrays + args = core_concat.apply( [], args ); + + var first, node, hasScripts, + scripts, doc, fragment, + i = 0, + l = this.length, + set = this, + iNoClone = l - 1, + value = args[0], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) { + return this.each(function( index ) { + var self = set.eq( index ); + if ( isFunction ) { + args[0] = value.call( this, index, table ? self.html() : undefined ); + } + self.domManip( args, table, callback ); + }); + } + + if ( l ) { + fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + table = table && jQuery.nodeName( first, "tr" ); + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( + table && jQuery.nodeName( this[i], "table" ) ? + findOrAppend( this[i], "tbody" ) : + this[i], + node, + i + ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { + + if ( node.src ) { + // Hope ajax is available... + jQuery.ajax({ + url: node.src, + type: "GET", + dataType: "script", + async: false, + global: false, + "throws": true + }); + } else { + jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); + } + } + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + } + } + + return this; + } +}); + +function findOrAppend( elem, tag ) { + return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + var attr = elem.getAttributeNode("type"); + elem.type = ( attr && attr.specified ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + if ( match ) { + elem.type = match[1]; + } else { + elem.removeAttribute("type"); + } + return elem; +} + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var elem, + i = 0; + for ( ; (elem = elems[i]) != null; i++ ) { + jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); + } +} + +function cloneCopyEvent( src, dest ) { + + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function fixCloneNodeIssues( src, dest ) { + var nodeName, e, data; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + nodeName = dest.nodeName.toLowerCase(); + + // IE6-8 copies events bound via attachEvent when using cloneNode. + if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) { + data = jQuery._data( dest ); + + for ( e in data.events ) { + jQuery.removeEvent( dest, e, data.handle ); + } + + // Event data gets referenced instead of copied if the expando gets copied too + dest.removeAttribute( jQuery.expando ); + } + + // IE blanks contents when cloning scripts, and tries to evaluate newly-set text + if ( nodeName === "script" && dest.text !== src.text ) { + disableScript( dest ).text = src.text; + restoreScript( dest ); + + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + } else if ( nodeName === "object" ) { + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) { + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.defaultSelected = dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + i = 0, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone(true); + jQuery( insert[i] )[ original ]( elems ); + + // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() + core_push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +}); + +function getAll( context, tag ) { + var elems, elem, + i = 0, + found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) : + undefined; + + if ( !found ) { + for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { + if ( !tag || jQuery.nodeName( elem, tag ) ) { + found.push( elem ); + } else { + jQuery.merge( found, getAll( elem, tag ) ); + } + } + } + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], found ) : + found; +} + +// Used in buildFragment, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( manipulation_rcheckableType.test( elem.type ) ) { + elem.defaultChecked = elem.checked; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var destElements, node, clone, i, srcElements, + inPage = jQuery.contains( elem.ownerDocument, elem ); + + if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && + (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + // Fix all IE cloning issues + for ( i = 0; (node = srcElements[i]) != null; ++i ) { + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + fixCloneNodeIssues( node, destElements[i] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0; (node = srcElements[i]) != null; i++ ) { + cloneCopyEvent( node, destElements[i] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + destElements = srcElements = node = null; + + // Return the cloned set + return clone; + }, + + buildFragment: function( elems, context, scripts, selection ) { + var j, elem, contains, + tmp, tag, tbody, wrap, + l = elems.length, + + // Ensure a safe fragment + safe = createSafeFragment( context ), + + nodes = [], + i = 0; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || safe.appendChild( context.createElement("div") ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + + tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; + + // Descend through wrappers to the right content + j = wrap[0]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Manually add leading whitespace removed by IE + if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); + } + + // Remove IE's autoinserted from table fragments + if ( !jQuery.support.tbody ) { + + // String was a , *may* have spurious + elem = tag === "table" && !rtbody.test( elem ) ? + tmp.firstChild : + + // String was a bare or + wrap[1] === "
" && !rtbody.test( elem ) ? + tmp : + 0; + + j = elem && elem.childNodes.length; + while ( j-- ) { + if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { + elem.removeChild( tbody ); + } + } + } + + jQuery.merge( nodes, tmp.childNodes ); + + // Fix #12392 for WebKit and IE > 9 + tmp.textContent = ""; + + // Fix #12392 for oldIE + while ( tmp.firstChild ) { + tmp.removeChild( tmp.firstChild ); + } + + // Remember the top-level container for proper cleanup + tmp = safe.lastChild; + } + } + } + + // Fix #11356: Clear elements from fragment + if ( tmp ) { + safe.removeChild( tmp ); + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !jQuery.support.appendChecked ) { + jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); + } + + i = 0; + while ( (elem = nodes[ i++ ]) ) { + + // #4087 - If origin and destination elements are the same, and this is + // that element, do not do anything + if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( safe.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( (elem = tmp[ j++ ]) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + tmp = null; + + return safe; + }, + + cleanData: function( elems, /* internal */ acceptData ) { + var elem, type, id, data, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + deleteExpando = jQuery.support.deleteExpando, + special = jQuery.event.special; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( acceptData || jQuery.acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( deleteExpando ) { + delete elem[ internalKey ]; + + } else if ( typeof elem.removeAttribute !== core_strundefined ) { + elem.removeAttribute( internalKey ); + + } else { + elem[ internalKey ] = null; + } + + core_deletedIds.push( id ); + } + } + } + } + } +}); +var iframe, getStyles, curCSS, + ralpha = /alpha\([^)]*\)/i, + ropacity = /opacity\s*=\s*([^)]*)/, + rposition = /^(top|right|bottom|left)$/, + // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" + // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rmargin = /^margin/, + rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), + rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), + rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ), + elemdisplay = { BODY: "block" }, + + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: 0, + fontWeight: 400 + }, + + cssExpand = [ "Top", "Right", "Bottom", "Left" ], + cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; + +// return a css property mapped to a potentially vendor prefixed property +function vendorPropName( style, name ) { + + // shortcut for names that are not vendor prefixed + if ( name in style ) { + return name; + } + + // check for vendor prefixed names + var capName = name.charAt(0).toUpperCase() + name.slice(1), + origName = name, + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in style ) { + return name; + } + } + + return origName; +} + +function isHidden( elem, el ) { + // isHidden might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); +} + +function showHide( elements, show ) { + var display, elem, hidden, + values = [], + index = 0, + length = elements.length; + + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + values[ index ] = jQuery._data( elem, "olddisplay" ); + display = elem.style.display; + if ( show ) { + // Reset the inline display of this element to learn if it is + // being hidden by cascaded rules or not + if ( !values[ index ] && display === "none" ) { + elem.style.display = ""; + } + + // Set elements which have been overridden with display: none + // in a stylesheet to whatever the default browser style is + // for such an element + if ( elem.style.display === "" && isHidden( elem ) ) { + values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); + } + } else { + + if ( !values[ index ] ) { + hidden = isHidden( elem ); + + if ( display && display !== "none" || !hidden ) { + jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) ); + } + } + } + } + + // Set the display of most of the elements in a second loop + // to avoid the constant reflow + for ( index = 0; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + if ( !show || elem.style.display === "none" || elem.style.display === "" ) { + elem.style.display = show ? values[ index ] || "" : "none"; + } + } + + return elements; +} + +jQuery.fn.extend({ + css: function( name, value ) { + return jQuery.access( this, function( elem, name, value ) { + var len, styles, + map = {}, + i = 0; + + if ( jQuery.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + }, + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + var bool = typeof state === "boolean"; + + return this.each(function() { + if ( bool ? state : isHidden( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + }); + } +}); + +jQuery.extend({ + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Exclude the following css properties to add px + cssNumber: { + "columnCount": true, + "fillOpacity": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + // normalize float css property + "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + style = elem.style; + + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // convert relative number strings (+= or -=) to relative numbers. #7345 + if ( type === "string" && (ret = rrelNum.exec( value )) ) { + value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); + // Fixes bug #9237 + type = "number"; + } + + // Make sure that NaN and null values aren't set. See: #7116 + if ( value == null || type === "number" && isNaN( value ) ) { + return; + } + + // If a number was passed in, add 'px' to the (except for certain CSS properties) + if ( type === "number" && !jQuery.cssNumber[ origName ] ) { + value += "px"; + } + + // Fixes #8908, it can be done more correctly by specifing setters in cssHooks, + // but it would mean to define eight (for every problematic property) identical functions + if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { + + // Wrapped to prevent IE from throwing errors when 'invalid' values are provided + // Fixes bug #5509 + try { + style[ name ] = value; + } catch(e) {} + } + + } else { + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var num, val, hooks, + origName = jQuery.camelCase( name ); + + // Make sure that we're working with the right name + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + //convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Return, converting to number if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; + } + return val; + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; + } +}); + +// NOTE: we've included the "window" in window.getComputedStyle +// because jsdom on node.js will break without it. +if ( window.getComputedStyle ) { + getStyles = function( elem ) { + return window.getComputedStyle( elem, null ); + }; + + curCSS = function( elem, name, _computed ) { + var width, minWidth, maxWidth, + computed = _computed || getStyles( elem ), + + // getPropertyValue is only needed for .css('filter') in IE9, see #12537 + ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined, + style = elem.style; + + if ( computed ) { + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right + // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels + // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values + if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret; + }; +} else if ( document.documentElement.currentStyle ) { + getStyles = function( elem ) { + return elem.currentStyle; + }; + + curCSS = function( elem, name, _computed ) { + var left, rs, rsLeft, + computed = _computed || getStyles( elem ), + ret = computed ? computed[ name ] : undefined, + style = elem.style; + + // Avoid setting ret to empty string here + // so we don't default to auto + if ( ret == null && style && style[ name ] ) { + ret = style[ name ]; + } + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + // but not position css attributes, as those are proportional to the parent element instead + // and we can't measure the parent instead because it might trigger a "stacking dolls" problem + if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { + + // Remember the original values + left = style.left; + rs = elem.runtimeStyle; + rsLeft = rs && rs.left; + + // Put in the new values to get a computed value out + if ( rsLeft ) { + rs.left = elem.currentStyle.left; + } + style.left = name === "fontSize" ? "1em" : ret; + ret = style.pixelLeft + "px"; + + // Revert the changed values + style.left = left; + if ( rsLeft ) { + rs.left = rsLeft; + } + } + + return ret === "" ? "auto" : ret; + }; +} + +function setPositiveNumber( elem, value, subtract ) { + var matches = rnumsplit.exec( value ); + return matches ? + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i = extra === ( isBorderBox ? "border" : "content" ) ? + // If we already have the right measurement, avoid augmentation + 4 : + // Otherwise initialize for horizontal or vertical properties + name === "width" ? 1 : 0, + + val = 0; + + for ( ; i < 4; i += 2 ) { + // both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // at this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + // at this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // at this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with offset property, which is equivalent to the border-box value + var valueIsBorderBox = true, + val = name === "width" ? elem.offsetWidth : elem.offsetHeight, + styles = getStyles( elem ), + isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // some non-html elements return undefined for offsetWidth, so check for null/undefined + // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 + // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 + if ( val <= 0 || val == null ) { + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name, styles ); + if ( val < 0 || val == null ) { + val = elem.style[ name ]; + } + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test(val) ) { + return val; + } + + // we need the check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + } + + // use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +// Try to determine the default display value of an element +function css_defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + // Use the already-created iframe if possible + iframe = ( iframe || + jQuery("