diff --git a/bin/drush-install.sh b/bin/drush-install.sh index 356173273cb..e1079a09a7b 100755 --- a/bin/drush-install.sh +++ b/bin/drush-install.sh @@ -11,6 +11,7 @@ uk.co.compucorp.civicrm.hremails ## List of extensions defining basic entity types ENTITY_EXTS=\ org.civicrm.hrbank,\ +org.civicrm.hrdemog,\ org.civicrm.hrjobcontract,\ com.civicrm.hrjobroles,\ org.civicrm.hrmed,\ diff --git a/bin/git-release.sh b/bin/git-release.sh index 4cd9dfd2411..8e774a84937 100755 --- a/bin/git-release.sh +++ b/bin/git-release.sh @@ -5,6 +5,7 @@ fileName="" ENTITY_EXTS=( hrbank \ hrcareer \ hrcase \ +hrdemog \ hrim \ hrmed \ hrprofile \ diff --git a/doc/INSTALL.md b/doc/INSTALL.md index ee4b8e25247..f58606fcc40 100644 --- a/doc/INSTALL.md +++ b/doc/INSTALL.md @@ -16,32 +16,4 @@ The [civihr-installer](https://github.com/compucorp/civihr-installer) script has $ civibuild create hr17 ``` -Read the drush-install.sh for details. - -## Install (Option B: Manual) - -CiviHR includes over a dozen extensions. These can be activated piecemeal. -The following extensions provide the major features and may be activated -individually: - - * org.civicrm.hrbank: Bank Details - * org.civicrm.hrcareer: Career History - * org.civicrm.hremerg: Emergency Contacts - * org.civicrm.hrabsence: Absences - * org.civicrm.hrjobcontract: Job Contracts - * org.civicrm.hrmed: Medical and Disability - * org.civicrm.hrqual: Qualifications - * org.civicrm.hrreport: Reporting - * org.civicrm.hrstaffdir: Staff Directory - * org.civicrm.hrcase: Case - * org.civicrm.hrcaseutils: Case Utils - * org.civicrm.hrim: Instant messanger link - * org.civicrm.hrrecruitment: Recruitment - * org.civicrm.hrprofile: Profile - -Finally, these two extensions build on top of the others: - - * uk.co.compucorp.civicrm.hrsampledata: Generate random example data - * org.civicrm.hrui: Trim/revise CiviCRM UI for CiviHR users - Please check the [civibuild documentation](https://docs.civicrm.org/dev/en/latest/tools/civibuild/) for more information on all the available params. diff --git a/hrdemog/CRM/HRDemog/Upgrader.php b/hrdemog/CRM/HRDemog/Upgrader.php new file mode 100644 index 00000000000..e32e54c4e78 --- /dev/null +++ b/hrdemog/CRM/HRDemog/Upgrader.php @@ -0,0 +1,185 @@ +executeSqlFile('sql/myinstall.sql'); + } + + /** + * Example: Run an external SQL script when the module is uninstalled + * + public function uninstall() { + $this->executeSqlFile('sql/myuninstall.sql'); + } + + /** + * Example: Run a simple query when a module is enabled + * + public function enable() { + CRM_Core_DAO::executeQuery('UPDATE foo SET is_active = 1 WHERE bar = "whiz"'); + } + + /** + * Example: Run a simple query when a module is disabled + * + public function disable() { + CRM_Core_DAO::executeQuery('UPDATE foo SET is_active = 0 WHERE bar = "whiz"'); + } + + /** + * Example: Run a couple simple queries + * + * @return TRUE on success + * @throws Exception + * + public function upgrade_4200() { + $this->ctx->log->info('Applying update 4200'); + CRM_Core_DAO::executeQuery('UPDATE foo SET bar = "whiz"'); + CRM_Core_DAO::executeQuery('DELETE FROM bang WHERE willy = wonka(2)'); + return TRUE; + } // */ + + + /** + * Example: Run an external SQL script + * + * @return TRUE on success + * @throws Exception + public function upgrade_4201() { + $this->ctx->log->info('Applying update 4201'); + // this path is relative to the extension base dir + $this->executeSqlFile('sql/upgrade_4201.sql'); + return TRUE; + } // */ + + + /** + * Example: Run a slow upgrade process by breaking it up into smaller chunk + * + * @return TRUE on success + * @throws Exception + public function upgrade_4202() { + $this->ctx->log->info('Planning update 4202'); // PEAR Log interface + + $this->addTask(ts('Process first step'), 'processPart1', $arg1, $arg2); + $this->addTask(ts('Process second step'), 'processPart2', $arg3, $arg4); + $this->addTask(ts('Process second step'), 'processPart3', $arg5); + return TRUE; + } + public function processPart1($arg1, $arg2) { sleep(10); return TRUE; } + public function processPart2($arg3, $arg4) { sleep(10); return TRUE; } + public function processPart3($arg5) { sleep(10); return TRUE; } + // */ + + + /** + * Example: Run an upgrade with a query that touches many (potentially + * millions) of records by breaking it up into smaller chunks. + * + * @return TRUE on success + * @throws Exception + public function upgrade_4203() { + $this->ctx->log->info('Planning update 4203'); // PEAR Log interface + + $minId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(min(id),0) FROM civicrm_contribution'); + $maxId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(max(id),0) FROM civicrm_contribution'); + for ($startId = $minId; $startId <= $maxId; $startId += self::BATCH_SIZE) { + $endId = $startId + self::BATCH_SIZE - 1; + $title = ts('Upgrade Batch (%1 => %2)', array( + 1 => $startId, + 2 => $endId, + )); + $sql = ' + UPDATE civicrm_contribution SET foobar = whiz(wonky()+wanker) + WHERE id BETWEEN %1 and %2 + '; + $params = array( + 1 => array($startId, 'Integer'), + 2 => array($endId, 'Integer'), + ); + $this->addTask($title, 'executeSql', $sql, $params); + } + return TRUE; + } // */ + + public function upgrade_1400() { + $this->ctx->log->info('Planning update 1400'); // PEAR Log interface + foreach (array('ethnicity_20130725123943', 'religion_20130725124132', 'sexual_orientation_20130725124348', 'marital_status_20130913084916') as $key => $value) { + $optParams = array( + 'option_group_id' => $value, + 'label' => 'Prefer Not to Say', + 'value' => 'Prefer Not to Say', + 'name' => 'Prefer_Not_to_Say', + ); + civicrm_api3('OptionValue', 'create', $optParams); + $optParam = array( + 'option_group_id' => $value, + 'label' => 'Not Applicable', + 'value' => 'Not Applicable', + 'name' => 'Not_Applicable', + ); + civicrm_api3('OptionValue', 'create', $optParam); + } + + $sql = "UPDATE civicrm_custom_field JOIN civicrm_custom_group ON civicrm_custom_group.id = civicrm_custom_field.custom_group_id SET civicrm_custom_field.default_value = CASE WHEN civicrm_custom_field.name = 'Ethnicity' THEN ' Not Applicable ' ELSE 'Not Applicable' END WHERE civicrm_custom_field.name IN ('Ethnicity','Religion', 'Sexual_Orientation', 'Marital_Status') AND civicrm_custom_group.name = 'Extended_Demographics'"; + CRM_Core_DAO::executeQuery($sql); + CRM_Core_DAO::executeQuery("UPDATE civicrm_custom_group SET is_reserved = 0, collapse_display = 1 where name = 'Extended_Demographics'"); + return TRUE; + } + + /** + * Upgrade CustomGroup, setting Extended_Demographics is_reserved value to YES + * + * @return bool + */ + public function upgrade_1401() { + $result = civicrm_api3('CustomGroup', 'get', [ + 'sequential' => 1, + 'return' => ['id'], + 'name' => 'Extended_Demographics', + ]); + + civicrm_api3('CustomGroup', 'create', [ + 'id' => $result['id'], + 'is_reserved' => 1, + ]); + + return TRUE; + } + +} diff --git a/hrdemog/CRM/HRDemog/Upgrader/Base.php b/hrdemog/CRM/HRDemog/Upgrader/Base.php new file mode 100644 index 00000000000..6e2a3fb9267 --- /dev/null +++ b/hrdemog/CRM/HRDemog/Upgrader/Base.php @@ -0,0 +1,298 @@ +ctx = array_shift($args); + $instance->queue = $instance->ctx->queue; + $method = array_shift($args); + return call_user_func_array(array($instance, $method), $args); + } + + public function __construct($extensionName, $extensionDir) { + $this->extensionName = $extensionName; + $this->extensionDir = $extensionDir; + } + + // ******** Task helpers ******** + + /** + * Run a CustomData file + * + * @param string $relativePath the CustomData XML file path (relative to this extension's dir) + * @return bool + */ + public function executeCustomDataFile($relativePath) { + $xml_file = $this->extensionDir . '/' . $relativePath; + return $this->executeCustomDataFileByAbsPath($xml_file); + } + + /** + * Run a CustomData file + * + * @param string $xml_file the CustomData XML file path (absolute path) + * @return bool + */ + protected static function executeCustomDataFileByAbsPath($xml_file) { + require_once 'CRM/Utils/Migrate/Import.php'; + $import = new CRM_Utils_Migrate_Import(); + $import->run($xml_file); + return TRUE; + } + + /** + * Run a SQL file + * + * @param string $relativePath the SQL file path (relative to this extension's dir) + * @return bool + */ + public function executeSqlFile($relativePath) { + CRM_Utils_File::sourceSQLFile( + CIVICRM_DSN, + $this->extensionDir . '/' . $relativePath + ); + return TRUE; + } + + /** + * Run one SQL query + * + * This is just a wrapper for CRM_Core_DAO::executeSql, but it + * provides syntatic sugar for queueing several tasks that + * run different queries + */ + public function executeSql($query, $params = array()) { + // FIXME verify that we raise an exception on error + CRM_Core_DAO::executeSql($query, $params); + return TRUE; + } + + /** + * Syntatic sugar for enqueuing a task which calls a function + * in this class. The task is weighted so that it is processed + * as part of the currently-pending revision. + * + * After passing the $funcName, you can also pass parameters that will go to + * the function. Note that all params must be serializable. + */ + public function addTask($title) { + $args = func_get_args(); + $title = array_shift($args); + $task = new CRM_Queue_Task( + array(get_class($this), '_queueAdapter'), + $args, + $title + ); + return $this->queue->createItem($task, array('weight' => -1)); + } + + // ******** Revision-tracking helpers ******** + + /** + * Determine if there are any pending revisions + * + * @return bool + */ + public function hasPendingRevisions() { + $revisions = $this->getRevisions(); + $currentRevision = $this->getCurrentRevision(); + + if (empty($revisions)) { + return FALSE; + } + if (empty($currentRevision)) { + return TRUE; + } + + return ($currentRevision < max($revisions)); + } + + /** + * Add any pending revisions to the queue + */ + public function enqueuePendingRevisions(CRM_Queue_Queue $queue) { + $this->queue = $queue; + + $currentRevision = $this->getCurrentRevision(); + foreach ($this->getRevisions() as $revision) { + if ($revision > $currentRevision) { + $title = ts('Upgrade %1 to revision %2', array( + 1 => $this->extensionName, + 2 => $revision, + )); + + // note: don't use addTask() because it sets weight=-1 + + $task = new CRM_Queue_Task( + array(get_class($this), '_queueAdapter'), + array('upgrade_' . $revision), + $title + ); + $this->queue->createItem($task); + + $task = new CRM_Queue_Task( + array(get_class($this), '_queueAdapter'), + array('setCurrentRevision', $revision), + $title + ); + $this->queue->createItem($task); + } + } + } + + /** + * Get a list of revisions + * + * @return array(revisionNumbers) sorted numerically + */ + public function getRevisions() { + if (! is_array($this->revisions)) { + $this->revisions = array(); + + $clazz = new ReflectionClass(get_class($this)); + $methods = $clazz->getMethods(); + foreach ($methods as $method) { + if (preg_match('/^upgrade_(.*)/', $method->name, $matches)) { + $this->revisions[] = $matches[1]; + } + } + sort($this->revisions, SORT_NUMERIC); + } + + return $this->revisions; + } + + public function getCurrentRevision() { + // return CRM_Core_BAO_Extension::getSchemaVersion($this->extensionName); + $key = $this->extensionName . ':version'; + return CRM_Core_BAO_Setting::getItem('Extension', $key); + } + + public function setCurrentRevision($revision) { + // We call this during hook_civicrm_install, but the underlying SQL + // UPDATE fails because the extension record hasn't been INSERTed yet. + // Instead, track revisions in our own namespace. + // CRM_Core_BAO_Extension::setSchemaVersion($this->extensionName, $revision); + + $key = $this->extensionName . ':version'; + CRM_Core_BAO_Setting::setItem($revision, 'Extension', $key); + return TRUE; + } + + // ******** Hook delegates ******** + + public function onInstall() { + $files = glob($this->extensionDir . '/sql/*_install.sql'); + if (is_array($files)) { + foreach ($files as $file) { + CRM_Utils_File::sourceSQLFile(CIVICRM_DSN, $file); + } + } + $files = glob($this->extensionDir . '/xml/*_install.xml'); + if (is_array($files)) { + foreach ($files as $file) { + $this->executeCustomDataFileByAbsPath($file); + } + } + if (is_callable(array($this, 'install'))) { + $this->install(); + } + $revisions = $this->getRevisions(); + if (!empty($revisions)) { + $this->setCurrentRevision(max($revisions)); + } + } + + public function onUninstall() { + if (is_callable(array($this, 'uninstall'))) { + $this->uninstall(); + } + $files = glob($this->extensionDir . '/sql/*_uninstall.sql'); + if (is_array($files)) { + foreach ($files as $file) { + CRM_Utils_File::sourceSQLFile(CIVICRM_DSN, $file); + } + } + $this->setCurrentRevision(NULL); + } + + public function onEnable() { + // stub for possible future use + if (is_callable(array($this, 'enable'))) { + $this->enable(); + } + } + + public function onDisable() { + // stub for possible future use + if (is_callable(array($this, 'disable'))) { + $this->disable(); + } + } + + public function onUpgrade($op, CRM_Queue_Queue $queue = NULL) { + switch($op) { + case 'check': + return array($this->hasPendingRevisions()); + case 'enqueue': + return $this->enqueuePendingRevisions($queue); + default: + } + } +} diff --git a/hrdemog/hrdemog.civix.php b/hrdemog/hrdemog.civix.php new file mode 100644 index 00000000000..6b646c8cd27 --- /dev/null +++ b/hrdemog/hrdemog.civix.php @@ -0,0 +1,215 @@ +template_dir ) ) { + array_unshift( $template->template_dir, $extDir ); + } else { + $template->template_dir = array( $extDir, $template->template_dir ); + } + + $include_path = $extRoot . PATH_SEPARATOR . get_include_path( ); + set_include_path( $include_path ); +} + +/** + * (Delegated) Implementation of hook_civicrm_xmlMenu + * + * @param $files array(string) + */ +function _hrdemog_civix_civicrm_xmlMenu(&$files) { + foreach (_hrdemog_civix_glob(__DIR__ . '/xml/Menu/*.xml') as $file) { + $files[] = $file; + } +} + +/** + * Implementation of hook_civicrm_install + */ +function _hrdemog_civix_civicrm_install() { + _hrdemog_civix_civicrm_config(); + if ($upgrader = _hrdemog_civix_upgrader()) { + return $upgrader->onInstall(); + } +} + +/** + * Implementation of hook_civicrm_uninstall + */ +function _hrdemog_civix_civicrm_uninstall() { + _hrdemog_civix_civicrm_config(); + if ($upgrader = _hrdemog_civix_upgrader()) { + return $upgrader->onUninstall(); + } +} + +/** + * (Delegated) Implementation of hook_civicrm_enable + */ +function _hrdemog_civix_civicrm_enable() { + _hrdemog_civix_civicrm_config(); + if ($upgrader = _hrdemog_civix_upgrader()) { + if (is_callable(array($upgrader, 'onEnable'))) { + return $upgrader->onEnable(); + } + } +} + +/** + * (Delegated) Implementation of hook_civicrm_disable + */ +function _hrdemog_civix_civicrm_disable() { + _hrdemog_civix_civicrm_config(); + if ($upgrader = _hrdemog_civix_upgrader()) { + if (is_callable(array($upgrader, 'onDisable'))) { + return $upgrader->onDisable(); + } + } +} + +/** + * (Delegated) Implementation of hook_civicrm_upgrade + * + * @param $op string, the type of operation being performed; 'check' or 'enqueue' + * @param $queue CRM_Queue_Queue, (for 'enqueue') the modifiable list of pending up upgrade tasks + * + * @return mixed based on op. for 'check', returns array(boolean) (TRUE if upgrades are pending) + * for 'enqueue', returns void + */ +function _hrdemog_civix_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) { + if ($upgrader = _hrdemog_civix_upgrader()) { + return $upgrader->onUpgrade($op, $queue); + } +} + +function _hrdemog_civix_upgrader() { + if (!file_exists(__DIR__.'/CRM/HRDemog/Upgrader.php')) { + return NULL; + } else { + return CRM_HRDemog_Upgrader_Base::instance(); + } +} + +/** + * Search directory tree for files which match a glob pattern + * + * Note: Dot-directories (like "..", ".git", or ".svn") will be ignored. + * Note: In Civi 4.3+, delegate to CRM_Utils_File::findFiles() + * + * @param $dir string, base dir + * @param $pattern string, glob pattern, eg "*.txt" + * @return array(string) + */ +function _hrdemog_civix_find_files($dir, $pattern) { + if (is_callable(array('CRM_Utils_File', 'findFiles'))) { + return CRM_Utils_File::findFiles($dir, $pattern); + } + + $todos = array($dir); + $result = array(); + while (!empty($todos)) { + $subdir = array_shift($todos); + foreach (_hrdemog_civix_glob("$subdir/$pattern") as $match) { + if (!is_dir($match)) { + $result[] = $match; + } + } + if ($dh = opendir($subdir)) { + while (FALSE !== ($entry = readdir($dh))) { + $path = $subdir . DIRECTORY_SEPARATOR . $entry; + if ($entry{0} == '.') { + } elseif (is_dir($path)) { + $todos[] = $path; + } + } + closedir($dh); + } + } + return $result; +} +/** + * (Delegated) Implementation of hook_civicrm_managed + * + * Find any *.mgd.php files, merge their content, and return. + */ +function _hrdemog_civix_civicrm_managed(&$entities) { + $mgdFiles = _hrdemog_civix_find_files(__DIR__, '*.mgd.php'); + foreach ($mgdFiles as $file) { + $es = include $file; + foreach ($es as $e) { + if (empty($e['module'])) { + $e['module'] = 'org.civicrm.hrdemog'; + } + $entities[] = $e; + } + } +} + +/** + * Glob wrapper which is guaranteed to return an array. + * + * The documentation for glob() says, "On some systems it is impossible to + * distinguish between empty match and an error." Anecdotally, the return + * result for an empty match is sometimes array() and sometimes FALSE. + * This wrapper provides consistency. + * + * @see http://php.net/glob + * @param string $pattern + * @return array, possibly empty + */ +function _hrdemog_civix_glob($pattern) { + $result = glob($pattern); + return is_array($result) ? $result : array(); +} + +/** + * Inserts a navigation menu item at a given place in the hierarchy + * + * $menu - menu hierarchy + * $path - path where insertion should happen (ie. Administer/System Settings) + * $item - menu you need to insert (parent/child attributes will be filled for you) + * $parentId - used internally to recurse in the menu structure + */ +function _hrdemog_civix_insert_navigation_menu(&$menu, $path, $item, $parentId = NULL) { + static $navId; + + // If we are done going down the path, insert menu + if (empty($path)) { + if (!$navId) $navId = CRM_Core_DAO::singleValueQuery("SELECT max(id) FROM civicrm_navigation"); + $navId ++; + $menu[$navId] = array ( + 'attributes' => array_merge($item, array( + 'label' => CRM_Utils_Array::value('name', $item), + 'active' => 1, + 'parentID' => $parentId, + 'navID' => $navId, + )) + ); + return true; + } else { + // Find an recurse into the next level down + $found = false; + $path = explode('/', $path); + $first = array_shift($path); + foreach ($menu as $key => &$entry) { + if ($entry['attributes']['name'] == $first) { + if (!$entry['child']) $entry['child'] = array(); + $found = _hrdemog_civix_insert_navigation_menu($entry['child'], implode('/', $path), $item, $key); + } + } + return $found; + } +} diff --git a/hrdemog/hrdemog.php b/hrdemog/hrdemog.php new file mode 100644 index 00000000000..fdff6261f3f --- /dev/null +++ b/hrdemog/hrdemog.php @@ -0,0 +1,116 @@ + "id",'name' => "Extended_Demographics",)); + civicrm_api3('CustomGroup', 'delete', array('id' => $customGroup['id'])); + //delete optionGroup + if ($visaGroupID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'is_visa_required_20130702051150', 'id', 'name')) { + CRM_Core_BAO_OptionGroup::del($visaGroupID); + } + return _hrdemog_civix_civicrm_uninstall(); +} + +/** + * Implementation of hook_civicrm_enable + */ +function hrdemog_civicrm_enable() { + _hrdemog_setActiveFields(1); + return _hrdemog_civix_civicrm_enable(); +} + +/** + * Implementation of hook_civicrm_disable + */ +function hrdemog_civicrm_disable() { + _hrdemog_setActiveFields(0); + return _hrdemog_civix_civicrm_disable(); +} + +function _hrdemog_setActiveFields($setActive) { + //disable/enable customgroup and customvalue + $sql = "UPDATE civicrm_custom_field JOIN civicrm_custom_group on civicrm_custom_group.id = civicrm_custom_field.custom_group_id SET civicrm_custom_field.is_active = {$setActive} WHERE civicrm_custom_group.name = 'Extended_Demographics'"; + CRM_Core_DAO::executeQuery($sql); + CRM_Core_DAO::executeQuery("UPDATE civicrm_custom_group SET is_active = {$setActive} WHERE name = 'Extended_Demographics'"); + + //disable/enable optionGroup and optionValue + $query = "UPDATE civicrm_option_value JOIN civicrm_option_group on civicrm_option_group.id = civicrm_option_value.option_group_id SET civicrm_option_value.is_active = {$setActive} WHERE civicrm_option_group.name IN ('ethnicity_20130725123943','religion_20130725124132','sexual_orientation_20130725124348','marital_status_20130913084916','is_visa_required_20130702051150')"; + CRM_Core_DAO::executeQuery($query); + CRM_Core_DAO::executeQuery("UPDATE civicrm_option_group SET is_active = {$setActive} WHERE name IN ('ethnicity_20130725123943','religion_20130725124132','sexual_orientation_20130725124348','marital_status_20130913084916','is_visa_required_20130702051150')"); +} + + +/** + * Implementation of hook_civicrm_upgrade + * + * @param $op string, the type of operation being performed; 'check' or 'enqueue' + * @param $queue CRM_Queue_Queue, (for 'enqueue') the modifiable list of pending up upgrade tasks + * + * @return mixed based on op. for 'check', returns array(boolean) (TRUE if upgrades are pending) + * for 'enqueue', returns void + */ +function hrdemog_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) { + return _hrdemog_civix_civicrm_upgrade($op, $queue); +} + +/** + * Implementation of hook_civicrm_managed + * + * Generate a list of entities to create/deactivate/delete when this module + * is installed, disabled, uninstalled. + */ +function hrdemog_civicrm_managed(&$entities) { + return _hrdemog_civix_civicrm_managed($entities); +} diff --git a/hrdemog/info.xml b/hrdemog/info.xml new file mode 100644 index 00000000000..5df28806d93 --- /dev/null +++ b/hrdemog/info.xml @@ -0,0 +1,20 @@ + + + hrdemog + Extended Demographics + Add extended demographic fields for the contact + AGPL-3.0 + + CiviCRM LLC + info@civicrm.org + + 2018-06-05 + 1.7.7 + stable + + 4.7 + + + CRM/HRDemog + + diff --git a/uk.co.compucorp.civicrm.hrcore/xml/CustomGroups/extended_demographics_install.xml b/hrdemog/xml/auto_install.xml similarity index 100% rename from uk.co.compucorp.civicrm.hrcore/xml/CustomGroups/extended_demographics_install.xml rename to hrdemog/xml/auto_install.xml diff --git a/hrui/js/dist/hrui.min.js b/hrui/js/dist/hrui.min.js index 78788ce52f9..609b9715b63 100644 --- a/hrui/js/dist/hrui.min.js +++ b/hrui/js/dist/hrui.min.js @@ -1,5 +1,5 @@ !function(t,o){function n(o){o&&o.departments&&o.departments.length>0?t(".crm-contact-detail-departments").html("Department: "+o.departments.join(", ")):t(".crm-contact-detail-departments").html("")}t(document).on("crmLoad",function(o){t(".crm-inline-edit").one("DOMSubtreeModified",function(){var o=t(this).find("form");1===o.length&&o.find("label").each(function(){var o=t(this),n=o.attr("for");t("#"+n).attr("placeholder",o.text())})})}).on("updateContactHeader",function(o,c){var a;void 0!==c.contract&&((a=c.contract)?(t(".crm-summary-contactname-block").removeClass("crm-summary-contactname-block-without-contract"),a.position&&t(".crm-contact-detail-position").html("Position: "+a.position),a.location&&t(".crm-contact-detail-location").html("Normal place of work: "+a.location)):(t(".crm-summary-contactname-block").addClass("crm-summary-contactname-block-without-contract"),t(".crm-contact-detail-position").html(""),t(".crm-contact-detail-location").html(""),n(null))),void 0!==c.roles&&n(c.roles)})}(CRM.$,CRM._); -!function(e,t){function a(){var t=e(this)[0].files[0];e("#js-uploaded-file").remove(),void 0!==t&&(e(this).after(''+t.name+' Remove'),e(".uploaded-file-icon-trash").on("click",r))}function o(e){e.find("label").attr("for",e.find(".crm-form-date").attr("id"))}function r(){var t=e("#js-uploaded-file").parent().find('input[type="file"]');e("#js-uploaded-file").remove(),t.val("")}function n(t){e(t).removeClass("crm-collapsible collapsed").addClass("crm-summary-block").appendTo(".contactTopBar .contactCardLeft").find(".collapsible-title").hide().end().find(".crm-summary-block").show()}e(document).on("crmLoad",function(t){var r,n,i;1===e(r="input[type='file']").length&&e(r).on("change",a),1===e(".CRM_HRRecruitment_Form_HRVacancy").length&&(o(e('label[for="start_date"]').parents("tr")),o(e('label[for="end_date"]').parents("tr")),e('[name="entryURL"]').val().indexOf(";template=1")>-1&&e(e(".CRM_HRRecruitment_Form_HRVacancy tbody").get(0)).addClass("CRM_HRRecruitment_Form_HRVacancy_Template")),n=t,"contactForm"!==CRM.formName&&"viewSummary"!==CRM.pageName||(e(".crm-contact-job_title",".crm-summary-contactinfo-block").length&&e(".crm-contact-tabs-list #tab_summary a",n.target).text("Personal Details"),n.target,e("#customFields").length<1&&e("#Inline_Custom_Data").detach().find(".label").each(function(){var t=e(this),a=t.next(),o=e("");o.append(t.find("label")),o.append(e("
")),o.append(a.html()),e("#nick_name").parent().after(o)}),i=n.target,e("div.crm-contact-current_employer, div.crm-contact-job_title",".crm-summary-contactinfo-block").parent("div.crm-summary-row").hide(),e("form#ContactInfo input#employer_id, form#ContactInfo input#job_title",i).closest("div.crm-summary-row").hide(),e("input#employer_id, input#job_title","form#Contact").parent("td").hide(),e(".HRJobContract_Summary",i).insertBefore(e(".crm-summary-contactinfo-block")),e("div.email-signature, td#Email-Bulkmail-html","form#Contact").hide(),e("#Email-Primary","form#Contact").prev("td").prev("td").hide(),e("td#Email-Bulkmail-html, #Email-Primary","form#Contact").prev("td").hide(),e(".crm-demographics-accordion","form#Contact").insertAfter(e(".crm-contactDetails-accordion")),e("tr#Phone_Block_2","form#Contact").length<1&&e("#addPhone").click()),e("#activityCustomData").attr("colspan",3),e("#crm-activity-view-table .crm-case-activity-view-Client .label").html("Contact"),e("span.crm-frozen-field",".crm-profile-name-hrident_tab").closest("div").parent("div").hide(),e(".crm-accordion-header.crm-master-accordion-header").on("click",function(){window.setTimeout(function(){Array.prototype.forEach.call(document.querySelectorAll(".listing-box"),function(e){Ps.initialize(e)})},0)}),e("INPUT#contact_source").parent("td").children("a").click(function(){e("#crm-notification-container .crm-help .notify-content").remove(),e("#crm-notification-container .crm-help p").length&&e("#crm-notification-container .crm-help p").remove(),e("#crm-notification-container .crm-help").append("

Source is a useful field where data has been migrated to CiviHR from one or a number of other legacy systems. The Source field will indicate which legacy system the contact has come from.

")})}).ready(function(){var t,a,o,r,n,i;e.ajax("/civicrm/hrcore/usermenu?snippet=4",{dataType:"html",success:function(t){var a,o,r;a="civihr-menu",o=e(t),(r=e("
")).attr("id",a),r.append(e("#civicrm-menu")),r.append(o),r.insertAfter("#page")}}),t=e(".crm-link-home"),a=e(".crm-logo-sm",t).addClass("chr_logo chr_logo--default-color").removeClass("crm-logo-sm").wrap('').parent(),r=a,o=e("li > a",t).first().text("Home").wrapInner('').prepend(r),n=o,t.off().find("#civicrm-home").before(n).remove(),e(".CRM_HRRecruitment_Form_Application").addClass("crm-form-block"),e(".CRM_HRRecruitment_Form_Application .crm-profile-name-application_profile").addClass("form-layout-compressed"),e("#root-menu-div .menu-item-arrow").each(function(t){var a=e(this);a.before(''),a.remove()}),i="activetarget",e(".menumain").not(".crm-Self_Service_Portal").hover(function(){e(this).addClass(i)},function(){e(this).removeClass(i)})}),e(".Inline_Custom_Data").length&&n(".Inline_Custom_Data"),n(".Extended_Demographics")}(CRM.$,CRM._); +!function(e,t){function a(){var t=e(this)[0].files[0];e("#js-uploaded-file").remove(),void 0!==t&&(e(this).after(''+t.name+' Remove'),e(".uploaded-file-icon-trash").on("click",o))}function r(e){e.find("label").attr("for",e.find(".crm-form-date").attr("id"))}function o(){var t=e("#js-uploaded-file").parent().find('input[type="file"]');e("#js-uploaded-file").remove(),t.val("")}e(document).on("crmLoad",function(t){var o,i,n;1===e(o="input[type='file']").length&&e(o).on("change",a),1===e(".CRM_HRRecruitment_Form_HRVacancy").length&&(r(e('label[for="start_date"]').parents("tr")),r(e('label[for="end_date"]').parents("tr")),e('[name="entryURL"]').val().indexOf(";template=1")>-1&&e(e(".CRM_HRRecruitment_Form_HRVacancy tbody").get(0)).addClass("CRM_HRRecruitment_Form_HRVacancy_Template")),i=t,"contactForm"!==CRM.formName&&"viewSummary"!==CRM.pageName||(e(".crm-contact-job_title",".crm-summary-contactinfo-block").length&&e(".crm-contact-tabs-list #tab_summary a",i.target).text("Personal Details"),i.target,e(".Inline_Custom_Data").length&&e(".Inline_Custom_Data").removeClass("crm-collapsible collapsed").addClass("crm-summary-block").insertAfter(".crm-summary-contactinfo-block").find(".collapsible-title").hide().end().find(".crm-summary-block").show(),e("#customFields").length<1&&e("#Inline_Custom_Data").detach().find(".label").each(function(){var t=e(this),a=t.next(),r=e("");r.append(t.find("label")),r.append(e("
")),r.append(a.html()),e("#nick_name").parent().after(r)}),n=i.target,e("div.crm-contact-current_employer, div.crm-contact-job_title",".crm-summary-contactinfo-block").parent("div.crm-summary-row").hide(),e("form#ContactInfo input#employer_id, form#ContactInfo input#job_title",n).closest("div.crm-summary-row").hide(),e("input#employer_id, input#job_title","form#Contact").parent("td").hide(),e(".HRJobContract_Summary",n).insertBefore(e(".crm-summary-contactinfo-block")),e("div.email-signature, td#Email-Bulkmail-html","form#Contact").hide(),e("#Email-Primary","form#Contact").prev("td").prev("td").hide(),e("td#Email-Bulkmail-html, #Email-Primary","form#Contact").prev("td").hide(),e(".crm-demographics-accordion","form#Contact").insertAfter(e(".crm-contactDetails-accordion")),e("tr#Phone_Block_2","form#Contact").length<1&&e("#addPhone").click()),e("#activityCustomData").attr("colspan",3),e("#crm-activity-view-table .crm-case-activity-view-Client .label").html("Contact"),e("span.crm-frozen-field",".crm-profile-name-hrident_tab").closest("div").parent("div").hide(),e(".crm-accordion-header.crm-master-accordion-header").on("click",function(){window.setTimeout(function(){Array.prototype.forEach.call(document.querySelectorAll(".listing-box"),function(e){Ps.initialize(e)})},0)}),e("INPUT#contact_source").parent("td").children("a").click(function(){e("#crm-notification-container .crm-help .notify-content").remove(),e("#crm-notification-container .crm-help p").length&&e("#crm-notification-container .crm-help p").remove(),e("#crm-notification-container .crm-help").append("

Source is a useful field where data has been migrated to CiviHR from one or a number of other legacy systems. The Source field will indicate which legacy system the contact has come from.

")})}).ready(function(){var t,a,r,o,i,n;e.ajax("/civicrm/hrcore/usermenu?snippet=4",{dataType:"html",success:function(t){var a,r,o;a="civihr-menu",r=e(t),(o=e("
")).attr("id",a),o.append(e("#civicrm-menu")),o.append(r),o.insertAfter("#page")}}),t=e(".crm-link-home"),a=e(".crm-logo-sm",t).addClass("chr_logo chr_logo--default-color").removeClass("crm-logo-sm").wrap('').parent(),o=a,r=e("li > a",t).first().text("Home").wrapInner('').prepend(o),i=r,t.off().find("#civicrm-home").before(i).remove(),e(".CRM_HRRecruitment_Form_Application").addClass("crm-form-block"),e(".CRM_HRRecruitment_Form_Application .crm-profile-name-application_profile").addClass("form-layout-compressed"),e("#root-menu-div .menu-item-arrow").each(function(t){var a=e(this);a.before(''),a.remove()}),n="activetarget",e(".menumain").not(".crm-Self_Service_Portal").hover(function(){e(this).addClass(n)},function(){e(this).removeClass(n)})})}(CRM.$,CRM._); !function(t){"use strict";var n=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;t.fn.attrchange=function(t){if(n){var e={subtree:!1,attributes:!0},i=new n(function(n){n.forEach(function(n){t.call(n.target,n)})});return this.each(function(){i.observe(this,e)})}}}(CRM.$); !function(t){"use strict";var i=t("body");i.on("click","#bootstrap-theme .btn-slide",function(){var n,a,e=t(this),o=e.children("ul.panel");function c(){t(".civihr-popup").remove(),i.removeClass("civihr-popup-open")}c(),n=o.clone(!0).appendTo(i).addClass("civihr-popup"),a=e.offset(),n.css({left:+a.left-(n.width()-e.outerWidth()),top:+a.top+e.outerHeight()}),n.show(),i.addClass("civihr-popup-open"),n.find("a").click(function(){var i=t(this).parent().index();o.find("li:nth("+i+") a").click()}),e.data("attrchange-is-on")||(e.data("attrchange-is-on",!0),e.attrchange(function(){e.hasClass("btn-slide-active")||c()}))})}(CRM.$); -//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImNvbnRhY3QuanMiLCJocnVpLmpzIiwiY2l2aWhyLXBvcHVwL2F0dHJjaGFuZ2UuanMiLCJjaXZpaHItcG9wdXAvY2l2aWhyLXBvcHVwLmpzIl0sIm5hbWVzIjpbIiQiLCJfIiwidXBkYXRlQ29udGFjdEhlYWRlclJvbGVzRGV0YWlscyIsInJvbGVzIiwiZGVwYXJ0bWVudHMiLCJsZW5ndGgiLCJodG1sIiwiam9pbiIsImRvY3VtZW50Iiwib24iLCJlIiwib25lIiwiJGZvcm0iLCJ0aGlzIiwiZmluZCIsImVhY2giLCIkbGFiZWwiLCJpZCIsImF0dHIiLCJ0ZXh0IiwiZGF0YSIsImNvbnRyYWN0IiwicmVtb3ZlQ2xhc3MiLCJwb3NpdGlvbiIsImxvY2F0aW9uIiwiYWRkQ2xhc3MiLCJDUk0iLCJpbnNlcnRGaWxlIiwiZmlsZU5hbWUiLCJmaWxlcyIsInJlbW92ZSIsInVuZGVmaW5lZCIsImFmdGVyIiwibmFtZSIsInJlbW92ZUZpbGUiLCJsaW5rTGFiZWxUb0RhdGVwaWNrZXJJbnB1dCIsIiRsaW5lIiwiJGlucHV0IiwicGFyZW50IiwidmFsIiwicmVwb3NpdGlvblBlcnNvbmFsRGV0YWlsc0Jsb2NrIiwic2VsZWN0b3IiLCJhcHBlbmRUbyIsImhpZGUiLCJlbmQiLCJzaG93IiwidGFyZ2V0IiwicGFyZW50cyIsImluZGV4T2YiLCJnZXQiLCJmb3JtTmFtZSIsInBhZ2VOYW1lIiwiZGV0YWNoIiwiJGxhYmVsQ2VsbCIsIiRmaWVsZENlbGwiLCJuZXh0IiwiJG5ld1RkIiwiYXBwZW5kIiwiY2xvc2VzdCIsImluc2VydEJlZm9yZSIsInByZXYiLCJpbnNlcnRBZnRlciIsImNsaWNrIiwid2luZG93Iiwic2V0VGltZW91dCIsIkFycmF5IiwicHJvdG90eXBlIiwiZm9yRWFjaCIsImNhbGwiLCJxdWVyeVNlbGVjdG9yQWxsIiwiZWxlbWVudCIsIlBzIiwiaW5pdGlhbGl6ZSIsImNoaWxkcmVuIiwicmVhZHkiLCIkbWVudUl0ZW0iLCIkd3JhcHBlZExvZ28iLCIkY3VzdG9tSG9tZUxpbmsiLCIkYXBwTG9nbyIsIiRob21lTGluayIsImNsYXNzTmFtZSIsImFqYXgiLCJkYXRhVHlwZSIsInN1Y2Nlc3MiLCJtZW51TWFya3VwIiwid3JhcHBlcklkIiwiJG1lbnVNYXJrdXAiLCIkbWVudVdyYXBwZXIiLCJ3cmFwIiwiZmlyc3QiLCJ3cmFwSW5uZXIiLCJwcmVwZW5kIiwib2ZmIiwiYmVmb3JlIiwiJGVsZW1lbnQiLCIkYXJyb3ciLCJub3QiLCJob3ZlciIsIk11dGF0aW9uT2JzZXJ2ZXIiLCJXZWJLaXRNdXRhdGlvbk9ic2VydmVyIiwiTW96TXV0YXRpb25PYnNlcnZlciIsImZuIiwiYXR0cmNoYW5nZSIsImNhbGxiYWNrIiwib3B0aW9ucyIsInN1YnRyZWUiLCJhdHRyaWJ1dGVzIiwib2JzZXJ2ZXIiLCJtdXRhdGlvbnMiLCJvYnNlcnZlIiwiJGJvZHkiLCIkcG9wdXBDbG9uZSIsImJ1dHRvbk9mZnNldCIsIiRidXR0b24iLCIkcG9wdXAiLCJjbG9zZVBvcHVwUGFuZWxzIiwiY2xvbmUiLCJvZmZzZXQiLCJjc3MiLCJsZWZ0Iiwid2lkdGgiLCJvdXRlcldpZHRoIiwidG9wIiwib3V0ZXJIZWlnaHQiLCJhY3Rpb25JbmRleCIsImluZGV4IiwiaGFzQ2xhc3MiXSwibWFwcGluZ3MiOiJDQUFDLFNBQVVBLEVBQUdDLEdBdURaLFNBQVNDLEVBQWlDQyxHQUNwQ0EsR0FBU0EsRUFBTUMsYUFBZUQsRUFBTUMsWUFBWUMsT0FBUyxFQUMzREwsRUFBRSxtQ0FBbUNNLEtBQUssZ0NBQWtDSCxFQUFNQyxZQUFZRyxLQUFLLE9BRW5HUCxFQUFFLG1DQUFtQ00sS0FBSyxJQTFEOUNOLEVBQUVRLFVBQ0NDLEdBQUcsVUFBVyxTQUFVQyxHQUN2QlYsRUFBRSxvQkFBb0JXLElBQUkscUJBQXNCLFdBQzlDLElBQUlDLEVBQVFaLEVBQUVhLE1BQU1DLEtBQUssUUFFSixJQUFqQkYsRUFBTVAsUUFDUk8sRUFBTUUsS0FBSyxTQUFTQyxLQUFLLFdBQ3ZCLElBQUlDLEVBQVNoQixFQUFFYSxN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TTJGLE9BekIvQixDQTZCRzlFLElBQUkxQjtDQ25CUCxTQUFXQSxHQUNULGFBQ0EsSUFBSThHLEVBQVE5RyxFQUFFLFFBRWQ4RyxFQUFNckcsR0FBRyxRQUFTLDhCQUErQixXQUMvQyxJQUFJc0csRUF5RUVDLEVBeEVGQyxFQUFVakgsRUFBRWEsTUFDWnFHLEVBQVNELEVBQVF4QyxTQUFTLFlBYzlCLFNBQVMwQyxJQUNQbkgsRUFBRSxpQkFBaUI4QixTQUNuQmdGLEVBQU14RixZQUFZLHFCQWJsQjZGLElBcUJBSixFQUFjRyxFQUFPRSxPQUFNLEdBQ3hCMUUsU0FBU29FLEdBQ1RyRixTQUFTLGdCQTZDUnVGLEVBQWVDLEVBQVFJLFNBRTNCTixFQUFZTyxLQUNWQyxNQUFPUCxFQUFhTyxNQUFRUixFQUFZUyxRQUFVUCxFQUFRUSxjQUMxREMsS0FBTVYsRUFBYVUsSUFBTVQsRUFBUVUsZ0JBRW5DWixFQUFZbEUsT0FDWmlFLEVBQU1yRixTQUFTLHFCQW5CZnNGLEVBQVlqRyxLQUFLLEtBQUtnRCxNQUFNLFdBQzFCLElBQUk4RCxFQUFjNUgsRUFBRWEsTUFBTXlCLFNBQVN1RixRQUVuQ1gsRUFBT3BHLEtBQUssVUFBWThHLEVBQWMsT0FBTzlELFVBeEIzQ21ELEVBQVE3RixLQUFLLHNCQUlqQjZGLEVBQVE3RixLQUFLLG9CQUFvQixHQUNqQzZGLEVBQVFYLFdBQVcsV0FFYlcsRUFBUWEsU0FBUyxxQkFJckJYLFNBeERSLENBd0ZHekYsSUFBSTFCIiwiZmlsZSI6ImhydWkubWluLmpzIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uICgkLCBfKSB7XG4gICQoZG9jdW1lbnQpXG4gICAgLm9uKCdjcm1Mb2FkJywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICQoJy5jcm0taW5saW5lLWVkaXQnKS5vbmUoJ0RPTVN1YnRyZWVNb2RpZmllZCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyICRmb3JtID0gJCh0aGlzKS5maW5kKCdmb3JtJyk7XG5cbiAgICAgICAgaWYgKCRmb3JtLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICRmb3JtLmZpbmQoJ2xhYmVsJykuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgJGxhYmVsID0gJCh0aGlzKTtcbiAgICAgICAgICAgIHZhciBpZCA9ICRsYWJlbC5hdHRyKCdmb3InKTtcbiAgICAgICAgICAgICQoJyMnICsgaWQpLmF0dHIoJ3BsYWNlaG9sZGVyJywgJGxhYmVsLnRleHQoKSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pXG4gICAgLm9uKCd1cGRhdGVDb250YWN0SGVhZGVyJywgZnVuY3Rpb24gKGUsIGRhdGEpIHtcbiAgICAgIGlmICh0eXBlb2YgZGF0YS5jb250cmFjdCAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgdXBkYXRlQ29udGFjdEhlYWRlckNvbnRyYWN0RGV0YWlscyhkYXRhLmNvbnRyYWN0KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHR5cGVvZiBkYXRhLnJvbGVzICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICB1cGRhdGVDb250YWN0SGVhZGVyUm9sZXNEZXRhaWxzKGRhdGEucm9sZXMpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gIC8qKlxuICAgKiBVcGRhdGVzIHRoZSBjb250YWN0IGhlYWRlciB3aXRoIHRoZSBnaXZlbiBjb250cmFjdCBkZXRhaWxzXG4gICAqXG4gICAqIEBwYXJhbSAge29iamVjdH0gY29udHJhY3RcbiAgICovXG4gIGZ1bmN0aW9uIHVwZGF0ZUNvbnRhY3RIZWFkZXJDb250cmFjdERldGFpbHMgKGNvbnRyYWN0KSB7XG4gICAgaWYgKGNvbnRyYWN0KSB7XG4gICAgICAkKCcuY3JtLXN1bW1hcnktY29udGFjdG5hbWUtYmxvY2snKS5yZW1vdmVDbGFzcygnY3JtLXN1bW1hcnktY29udGFjdG5hbWUtYmxvY2std2l0aG91dC1jb250cmFjdCcpO1xuXG4gICAgICBpZiAoY29udHJhY3QucG9zaXRpb24pIHtcbiAgICAgICAgJCgnLmNybS1jb250YWN0LWRldGFpbC1wb3NpdGlvbicpLmh0bWwoJzxzdHJvbmc+UG9zaXRpb246PC9zdHJvbmc+ICcgKyBjb250cmFjdC5wb3NpdGlvbik7XG4gICAgICB9XG5cbiAgICAgIGlmIChjb250cmFjdC5sb2NhdGlvbikge1xuICAgICAgICAkKCcuY3JtLWNvbnRhY3QtZGV0YWlsLWxvY2F0aW9uJykuaHRtbCgnPHN0cm9uZz5Ob3JtYWwgcGxhY2Ugb2Ygd29yazo8L3N0cm9uZz4gJyArIGNvbnRyYWN0LmxvY2F0aW9uKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgJCgnLmNybS1zdW1tYXJ5LWNvbnRhY3RuYW1lLWJsb2NrJykuYWRkQ2xhc3MoJ2NybS1zdW1tYXJ5LWNvbnRhY3RuYW1lLWJsb2NrLXdpdGhvdXQtY29udHJhY3QnKTtcbiAgICAgICQoJy5jcm0tY29udGFjdC1kZXRhaWwtcG9zaXRpb24nKS5odG1sKCcnKTtcbiAgICAgICQoJy5jcm0tY29udGFjdC1kZXRhaWwtbG9jYXRpb24nKS5odG1sKCcnKTtcblxuICAgICAgdXBkYXRlQ29udGFjdEhlYWRlclJvbGVzRGV0YWlscyhudWxsKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlcyB0aGUgY29udGFjdCBoZWFkZXIgd2l0aCB0aGUgZ2l2ZW4gcm9sZXMgZGV0YWlsc1xuICAgKlxuICAgKiBAcGFyYW0gIHtvYmplY3R9IGNvbnRyYWN0XG4gICAqL1xuICBmdW5jdGlvbiB1cGRhdGVDb250YWN0SGVhZGVyUm9sZXNEZXRhaWxzIChyb2xlcykge1xuICAgIGlmIChyb2xlcyAmJiByb2xlcy5kZXBhcnRtZW50cyAmJiByb2xlcy5kZXBhcnRtZW50cy5sZW5ndGggPiAwKSB7XG4gICAgICAkKCcuY3JtLWNvbnRhY3QtZGV0YWlsLWRlcGFydG1lbnRzJykuaHRtbCgnPHN0cm9uZz5EZXBhcnRtZW50Ojwvc3Ryb25nPiAnICsgcm9sZXMuZGVwYXJ0bWVudHMuam9pbignLCAnKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICQoJy5jcm0tY29udGFjdC1kZXRhaWwtZGVwYXJ0bWVudHMnKS5odG1sKCcnKTtcbiAgICB9XG4gIH1cbn0oQ1JNLiQsIENSTS5fKSk7XG4iLCIvKiBnbG9iYWwgUHMgKi9cblxuLy8gQ29weXJpZ2h0IENpdmlDUk0gTExDIDIwMTMuIFNlZSBodHRwOi8vY2l2aWNybS5vcmcvbGljZW5zaW5nXG4oZnVuY3Rpb24gKCQsIF8pIHtcbiAgJChkb2N1bWVudClcbiAgICAub24oJ2NybUxvYWQnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgYWRkVXBsb2FkRmlsZUxpc3RlbmVyKFwiaW5wdXRbdHlwZT0nZmlsZSddXCIpO1xuICAgICAgYW1lbmRWYWNhbmN5Rm9ybSgpO1xuICAgICAgYW1lbmRDb250YWN0UGFnZUFuZEZvcm0oZSk7XG4gICAgICBhcHBseU1pc2NDaGFuZ2VzKCk7XG4gICAgICBjaGFuZ2VDb250YWN0U291cmNlRmllbGRIZWxwVGV4dCgpO1xuICAgIH0pXG4gICAgLnJlYWR5KGZ1bmN0aW9uICgpIHtcbiAgICAgIGFkZFVzZXJNZW51VG9NYWluTWVudSgpO1xuICAgICAgYW1lbmRBcHBMb2dvTWVudUl0ZW0oKTtcbiAgICAgIGFtZW5kQXBwbGljYXRpb25Gb3JtKCk7XG4gICAgICB1c2VGb250QXdlc29tZUFycm93c0luU3ViTWVudUl0ZW1zKCk7XG4gICAgICB0b2dnbGVBY3RpdmVDbGFzc09uSG92ZXJPbkFueU1haW5NZW51SXRlbSgpO1xuICAgIH0pO1xuXG4gIC8qKlxuICAgKiBDdXN0b21pemVzIHRoZSBhcHAgbG9nbyBtZW51IGl0ZW0sIHN3aXRjaGluZyBmcm9tIHRoZSBDaXZpQ1JNIGxvZ29cbiAgICogdG8gdGhlIENpdmlIUiBsb2dvLCBhbmQgbWFraW5nIHRoZSBpdGVtIGEgZGlyZWN0IGxpbmsgaW5zdGVhZCBvZiBhXG4gICAqIHRvZ2dsZSBmb3IgYSBzdWIgbWVudSBkcm9wZG93blxuICAgKi9cbiAgZnVuY3Rpb24gYW1lbmRBcHBMb2dvTWVudUl0ZW0gKCkge1xuICAgIHZhciAkbWVudUl0ZW0gPSAkKCcuY3JtLWxpbmstaG9tZScpO1xuICAgIHZhciAkd3JhcHBlZExvZ28gPSBzd2FwQW5kV3JhcEFwcExvZ28oJG1lbnVJdGVtKTtcbiAgICB2YXIgJGN1c3RvbUhvbWVMaW5rID0gY3VzdG9taXplSG9tZUxpbmtJbkxvZ29NZW51SXRlbSgkbWVudUl0ZW0sICR3cmFwcGVkTG9nbyk7XG5cbiAgICByZW1vdmVMb2dvU3ViTWVudUFuZEtlZXBPbmx5SG9tZUxpbmsoJG1lbnVJdGVtLCAkY3VzdG9tSG9tZUxpbmspO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgdGhlIHVzZXIgbWVudSBieSBmZXRjaGluZyBpdCBmcm9tIHRoZSBocmNvcmUgZXh0ZW5zaW9uXG4gICAqL1xuICBmdW5jdGlvbiBhZGRVc2VyTWVudVRvTWFpbk1lbnUgKCkge1xuICAgICQuYWpheCgnL2Npdmljcm0vaHJjb3JlL3VzZXJtZW51P3NuaXBwZXQ9NCcsIHtcbiAgICAgIGRhdGFUeXBlOiAnaHRtbCcsXG4gICAgICBzdWNjZXNzOiBmdW5jdGlvbiAobWVudU1hcmt1cCkge1xuICAgICAgICBpbmplY3RVc2VyTWVudUluQU1haW5NZW51V3JhcHBlcihtZW51TWFya3VwLCAnY2l2aWhyLW1lbnUnKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYW4gZXZlbnQgbGlzdGVuZXIgb24gaW5wdXRbdHlwZT1cImZpbGVcIl1cbiAgICogQHBhcmFtIHtqUXVlcnkgT2JqZWN0fSBzZWxlY3RvciBbc2VsZWN0b3IgZnJvbSBpbnB1dCBmaWxlXVxuICAgKi9cbiAgZnVuY3Rpb24gYWRkVXBsb2FkRmlsZUxpc3RlbmVyIChzZWxlY3Rvcikge1xuICAgIGlmICgkKHNlbGVjdG9yKS5sZW5ndGggPT09IDEpIHtcbiAgICAgICQoc2VsZWN0b3IpLm9uKCdjaGFuZ2UnLCBpbnNlcnRGaWxlKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQW1lbmRzIHRoZSBhcHBsaWNhdGlvbiBmb3JtXG4gICAqL1xuICBmdW5jdGlvbiBhbWVuZEFwcGxpY2F0aW9uRm9ybSAoKSB7XG4gICAgJCgnLkNSTV9IUlJlY3J1aXRtZW50X0Zvcm1fQXBwbGljYXRpb24nKS5hZGRDbGFzcygnY3JtLWZvcm0tYmxvY2snKTtcbiAgICAkKCcuQ1JNX0hSUmVjcnVpdG1lbnRfRm9ybV9BcHBsaWNhdGlvbiAuY3JtLXByb2ZpbGUtbmFtZS1hcHBsaWNhdGlvbl9wcm9maWxlJykuYWRkQ2xhc3MoJ2Zvcm0tbGF5b3V0LWNvbXByZXNzZWQnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbWVuZHMgdGhlIGNvbnRhY3QgcGFnZSBhbmQgdGhlIGNvbnRhY3QgZm9ybVxuICAgKi9cbiAgZnVuY3Rpb24gYW1lbmRDb250YWN0UGFnZUFuZEZvcm0gKGUpIHtcbiAgICBpZiAoQ1JNLmZvcm1OYW1lID09PSAnY29udGFjdEZvcm0nIHx8IENSTS5wYWdlTmFtZSA9PT0gJ3ZpZXdTdW1tYXJ5Jykge1xuICAgICAgLy8gUmVuYW1lIFwiU3VtbWFyeVwiIHRhYiB0byBcIlBlcnNvbmFsIERldGFpbHNcIlxuICAgICAgLy8gSGFjayB0byBjaGVjayBjb250YWN0IHR5cGUgLSBUaGlzIGZpZWxkIG9ubHkgYXBwZWFycyBmb3IgaW5kaXZpZHVhbHNcbiAgICAgIGlmICgkKCcuY3JtLWNvbnRhY3Qtam9iX3RpdGxlJywgJy5jcm0tc3VtbWFyeS1jb250YWN0aW5mby1ibG9jaycpLmxlbmd0aCkge1xuICAgICAgICAkKCcuY3JtLWNvbnRhY3QtdGFicy1saXN0ICN0YWJfc3VtbWFyeSBhJywgZS50YXJnZXQpLnRleHQoJ1BlcnNvbmFsIERldGFpbHMnKTtcbiAgICAgIH1cblxuICAgICAgbWFuaXB1bGF0ZURPTU9mSW5saW5lQ3VzdG9tRGF0YShlLnRhcmdldCk7XG4gICAgICBtaXNjQ29udGFjdFBhZ2VDaGFuZ2VzKGUudGFyZ2V0KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQW1lbmRzIHRoZSB2YWNhbmN5IGZvcm1cbiAgICovXG4gIGZ1bmN0aW9uIGFtZW5kVmFjYW5jeUZvcm0gKCkge1xuICAgIGlmICgkKCcuQ1JNX0hSUmVjcnVpdG1lbnRfRm9ybV9IUlZhY2FuY3knKS5sZW5ndGggPT09IDEpIHtcbiAgICAgIGxpbmtMYWJlbFRvRGF0ZXBpY2tlcklucHV0KCQoJ2xhYmVsW2Zvcj1cInN0YXJ0X2RhdGVcIl0nKS5wYXJlbnRzKCd0cicpKTtcbiAgICAgIGxpbmtMYWJlbFRvRGF0ZXBpY2tlcklucHV0KCQoJ2xhYmVsW2Zvcj1cImVuZF9kYXRlXCJdJykucGFyZW50cygndHInKSk7XG5cbiAgICAgIC8vIEFkZCBhIGNsYXNzIHRvIGlkZW50aWZ5IHRoZSBmb3JtICdOZXcgVmFjYW5jeSBUZW1wbGF0ZSdcbiAgICAgIGlmICgkKCdbbmFtZT1cImVudHJ5VVJMXCJdJykudmFsKCkuaW5kZXhPZignO3RlbXBsYXRlPTEnKSA+IC0xKSB7XG4gICAgICAgICQoJCgnLkNSTV9IUlJlY3J1aXRtZW50X0Zvcm1fSFJWYWNhbmN5IHRib2R5JykuZ2V0KDApKS5hZGRDbGFzcygnQ1JNX0hSUmVjcnVpdG1lbnRfRm9ybV9IUlZhY2FuY3lfVGVtcGxhdGUnKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQXBwbGllcyBtaXNjZWxsYW5lb3VzIFVJIGNoYW5nZXNcbiAgICovXG4gIGZ1bmN0aW9uIGFwcGx5TWlzY0NoYW5nZXMgKCkge1xuICAgICQoJyNhY3Rpdml0eUN1c3RvbURhdGEnKS5hdHRyKCdjb2xzcGFuJywgMyk7XG4gICAgJCgnI2NybS1hY3Rpdml0eS12aWV3LXRhYmxlIC5jcm0tY2FzZS1hY3Rpdml0eS12aWV3LUNsaWVudCAubGFiZWwnKS5odG1sKCdDb250YWN0Jyk7XG4gICAgJCgnc3Bhbi5jcm0tZnJvemVuLWZpZWxkJywgJy5jcm0tcHJvZmlsZS1uYW1lLWhyaWRlbnRfdGFiJykuY2xvc2VzdCgnZGl2JykucGFyZW50KCdkaXYnKS5oaWRlKCk7XG5cbiAgICAkKCcuY3JtLWFjY29yZGlvbi1oZWFkZXIuY3JtLW1hc3Rlci1hY2NvcmRpb24taGVhZGVyJykub24oJ2NsaWNrJywgZnVuY3Rpb24gKCkge1xuICAgICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICBBcnJheS5wcm90b3R5cGUuZm9yRWFjaC5jYWxsKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy5saXN0aW5nLWJveCcpLCBmdW5jdGlvbiAoZWxlbWVudCkge1xuICAgICAgICAgIFBzLmluaXRpYWxpemUoZWxlbWVudCk7XG4gICAgICAgIH0pO1xuICAgICAgfSwgMCk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQ2hhbmdlcyBvZiBzb3JjZSBoZWxwIHRleHRcbiAgICovXG4gIGZ1bmN0aW9uIGNoYW5nZUNvbnRhY3RTb3VyY2VGaWVsZEhlbHBUZXh0ICgpIHtcbiAgICAkKCdJTlBVVCNjb250YWN0X3NvdXJjZScpLnBhcmVudCgndGQnKS5jaGlsZHJlbignYScpLmNsaWNrKGZ1bmN0aW9uICgpIHtcbiAgICAgICQoJyNjcm0tbm90aWZpY2F0aW9uLWNvbnRhaW5lciAuY3JtLWhlbHAgLm5vdGlmeS1jb250ZW50JykucmVtb3ZlKCk7XG5cbiAgICAgIGlmICgkKCcjY3JtLW5vdGlmaWNhdGlvbi1jb250YWluZXIgLmNybS1oZWxwIHAnKS5sZW5ndGgpIHtcbiAgICAgICAgJCgnI2NybS1ub3RpZmljYXRpb24tY29udGFpbmVyIC5jcm0taGVscCBwJykucmVtb3ZlKCk7XG4gICAgICB9XG5cbiAgICAgICQoJyNjcm0tbm90aWZpY2F0aW9uLWNvbnRhaW5lciAuY3JtLWhlbHAnKS5hcHBlbmQoJzxwPlNvdXJjZSBpcyBhIHVzZWZ1bCBmaWVsZCB3aGVyZSBkYXRhIGhhcyBiZWVuIG1pZ3JhdGVkIHRvIENpdmlIUiBmcm9tIG9uZSBvciBhIG51bWJlciBvZiBvdGhlciBsZWdhY3kgc3lzdGVtcy4gVGhlIFNvdXJjZSBmaWVsZCB3aWxsIGluZGljYXRlIHdoaWNoIGxlZ2FjeSBzeXN0ZW0gdGhlIGNvbnRhY3QgaGFzIGNvbWUgZnJvbS48L3A+Jyk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogRmluZHMgdGhlIG9yaWdpbmFsIGxpbmsgdG8gdGhlIGhvbWVwYWdlLCBjaGFuZ2VzIHRoZSB0ZXh0LCB3cmFwcyBpdCBpbiBhXG4gICAqIGBtZW51bWFpbi1sYWJlbGAgZWxlbWVudCBhbmQgcHJlcGVuZHMgaW50ZXJuYWxseSB0aGUgZ2l2ZW4gYXBwIGxvZ29cbiAgICpcbiAgICogQHBhcmFtIHtvYmplY3R9ICRtZW51SXRlbSBUaGUgY29udGV4dCB3aGVyZSB0byBmaW5kIHRoZSBsaW5rXG4gICAqIEBwYXJhbSB7b2JqZWN0fSAkYXBwTG9nb1xuICAgKiBAcmV0dXJuIHRoZSBjdXN0b21pemVkIGhvbWUgbGlua1xuICAgKi9cbiAgZnVuY3Rpb24gY3VzdG9taXplSG9tZUxpbmtJbkxvZ29NZW51SXRlbSAoJG1lbnVJdGVtLCAkYXBwTG9nbykge1xuICAgIHZhciAkaG9tZUxpbmsgPSAkKCdsaSA+IGEnLCAkbWVudUl0ZW0pLmZpcnN0KCk7XG5cbiAgICByZXR1cm4gJGhvbWVMaW5rXG4gICAgICAudGV4dCgnSG9tZScpXG4gICAgICAud3JhcElubmVyKCc8c3BhbiBjbGFzcz1cIm1lbnVtYWluLWxhYmVsXCI+JylcbiAgICAgIC5wcmVwZW5kKCRhcHBMb2dvKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbmplY3RzIHRoZSBnaXZlbiBtYXJrdXAgaW4gYSBtZW51IHdyYXBwZXIgd2l0aCB0aGUgZ2l2ZW4gaWRcbiAgICogY3JlYXRlZCB0byBjb250YWluIGJvdGggdGhlIG9yaWdpbmFsIG1lbnUgYW5kIHRoZSB1c2VyIG9uZVxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVudU1hcmt1cFxuICAgKiBAcGFyYW0ge3N0cmluZ30gd3JhcHBlcklkXG4gICAqL1xuICBmdW5jdGlvbiBpbmplY3RVc2VyTWVudUluQU1haW5NZW51V3JhcHBlciAobWVudU1hcmt1cCwgd3JhcHBlcklkKSB7XG4gICAgdmFyICRtZW51TWFya3VwID0gJChtZW51TWFya3VwKTtcbiAgICB2YXIgJG1lbnVXcmFwcGVyID0gJCgnPGRpdj4nKTtcblxuICAgICRtZW51V3JhcHBlci5hdHRyKCdpZCcsIHdyYXBwZXJJZCk7XG4gICAgJG1lbnVXcmFwcGVyLmFwcGVuZCgkKCcjY2l2aWNybS1tZW51JykpO1xuICAgICRtZW51V3JhcHBlci5hcHBlbmQoJG1lbnVNYXJrdXApO1xuICAgICRtZW51V3JhcHBlci5pbnNlcnRBZnRlcignI3BhZ2UnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnNlcnQgYSBET00gbm9kZSBhZnRlciBpbnB1dFt0eXBlPVwiZmlsZVwiXVxuICAgKiB3aXRoIHRoZSBmaWxlbmFtZVxuICAgKi9cbiAgZnVuY3Rpb24gaW5zZXJ0RmlsZSAoKSB7XG4gICAgdmFyIGZpbGVOYW1lID0gJCh0aGlzKVswXS5maWxlc1swXTtcblxuICAgICQoJyNqcy11cGxvYWRlZC1maWxlJykucmVtb3ZlKCk7XG4gICAgaWYgKGZpbGVOYW1lICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICQodGhpcykuYWZ0ZXIoJzxzcGFuIGlkPVwianMtdXBsb2FkZWQtZmlsZVwiIGNsYXNzPVwidXBsb2FkZWQtZmlsZVwiPicgKyBmaWxlTmFtZS5uYW1lICsgJyA8c3BhbiBjbGFzcz1cInVwbG9hZGVkLWZpbGUtaWNvbi10cmFzaFwiPjxpIGNsYXNzPVwiZmEgZmEtdHJhc2gtb1wiPjwvaT4gUmVtb3ZlPC9zcGFuPicpO1xuXG4gICAgICAkKCcudXBsb2FkZWQtZmlsZS1pY29uLXRyYXNoJykub24oJ2NsaWNrJywgcmVtb3ZlRmlsZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZSBsYWJlbCAnZm9yJyBhdHRyIHRvIHdvcmtzIHdpdGggdGhlIGRhdGVwaWNrZXJcbiAgICpcbiAgICogQHBhcmFtICB7alF1ZXJ5IG9iamVjdH0gJGxpbmUgW2RhdGVwaWNrZXIncyBsaW5lIHBhcmVudF1cbiAgICovXG4gIGZ1bmN0aW9uIGxpbmtMYWJlbFRvRGF0ZXBpY2tlcklucHV0ICgkbGluZSkge1xuICAgICRsaW5lLmZpbmQoJ2xhYmVsJykuYXR0cignZm9yJywgJGxpbmUuZmluZCgnLmNybS1mb3JtLWRhdGUnKS5hdHRyKCdpZCcpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNYW5pcHVsYXRlcywgYXQgdGhlIERPTSBsZXZlbCwgdGhlIGJsb2Nrcy9maWVsZHMgYmVsb25naW5nIHRvIHRoZVxuICAgKiBJbmxpbmUgQ3VzdG9tIERhdGEgY3VzdG9tIGZpZWxkcyBzZXRcbiAgICovXG4gIGlmICgkKCcuSW5saW5lX0N1c3RvbV9EYXRhJykubGVuZ3RoKSB7XG4gICAgcmVwb3NpdGlvblBlcnNvbmFsRGV0YWlsc0Jsb2NrKCcuSW5saW5lX0N1c3RvbV9EYXRhJyk7XG4gIH1cblxuICByZXBvc2l0aW9uUGVyc29uYWxEZXRhaWxzQmxvY2soJy5FeHRlbmRlZF9EZW1vZ3JhcGhpY3MnKTtcblxuICBmdW5jdGlvbiBtYW5pcHVsYXRlRE9NT2ZJbmxpbmVDdXN0b21EYXRhICgpIHtcbiAgICBpZiAoJCgnI2N1c3RvbUZpZWxkcycpLmxlbmd0aCA8IDEpIHtcbiAgICAgIHJlcG9zaXRpb25JbmxpbmVDdXN0b21EYXRhRmllbGRzSW5FZGl0Q29udGFjdEZvcm0oKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTWlzYyBjaGFuZ2VzIHRvIHRoZSBwYWdlIChoaWRpbmcgZWxlbWVudHMsIGluc2VydGluZyBuZXcgb25lcywgZXRjKVxuICAgKi9cbiAgZnVuY3Rpb24gbWlzY0NvbnRhY3RQYWdlQ2hhbmdlcyAodGFyZ2V0KSB7XG4gICAgLy8gSGlkZSBjdXJyZW50IGVtcGxveWVyIGFuZCBqb2IgdGl0bGVcbiAgICAvLyBDb250YWN0IHN1bW1hcnkgc2NyZWVuOlxuICAgICQoJ2Rpdi5jcm0tY29udGFjdC1jdXJyZW50X2VtcGxveWVyLCBkaXYuY3JtLWNvbnRhY3Qtam9iX3RpdGxlJywgJy5jcm0tc3VtbWFyeS1jb250YWN0aW5mby1ibG9jaycpLnBhcmVudCgnZGl2LmNybS1zdW1tYXJ5LXJvdycpLmhpZGUoKTtcbiAgICAvLyBJbmxpbmUgZWRpdCBmb3JtXG4gICAgJCgnZm9ybSNDb250YWN0SW5mbyBpbnB1dCNlbXBsb3llcl9pZCwgZm9ybSNDb250YWN0SW5mbyBpbnB1dCNqb2JfdGl0bGUnLCB0YXJnZXQpLmNsb3Nlc3QoJ2Rpdi5jcm0tc3VtbWFyeS1yb3cnKS5oaWRlKCk7XG4gICAgLy8gQ29udGFjdCBlZGl0IHNjcmVlblxuICAgICQoJ2lucHV0I2VtcGxveWVyX2lkLCBpbnB1dCNqb2JfdGl0bGUnLCAnZm9ybSNDb250YWN0JykucGFyZW50KCd0ZCcpLmhpZGUoKTtcblxuICAgIC8qIENoYW5nZXMgb24gQWRkIEluZGl2aWR1YWwgcGFnZXMgYW5kIFBlcnNvbmFsIGRldGFpbHMgdGFiIGZvciBIUi0zNTggKi9cbiAgICAvLyBNb3ZlIEpvYiBzdW1tYXJ5IHRvIHRvcFxuICAgICQoJy5IUkpvYkNvbnRyYWN0X1N1bW1hcnknLCB0YXJnZXQpLmluc2VydEJlZm9yZSgkKCcuY3JtLXN1bW1hcnktY29udGFjdGluZm8tYmxvY2snKSk7XG4gICAgLy8gY2hhbmdlcyBvZiBlbWFpbCBibG9jaywgcmVtb3ZlIGJ1bGttYWlsIGFuZCBvbmhvbGRcbiAgICAkKCdkaXYuZW1haWwtc2lnbmF0dXJlLCB0ZCNFbWFpbC1CdWxrbWFpbC1odG1sJywgJ2Zvcm0jQ29udGFjdCcpLmhpZGUoKTtcbiAgICAkKCcjRW1haWwtUHJpbWFyeScsICdmb3JtI0NvbnRhY3QnKS5wcmV2KCd0ZCcpLnByZXYoJ3RkJykuaGlkZSgpO1xuICAgICQoJ3RkI0VtYWlsLUJ1bGttYWlsLWh0bWwsICNFbWFpbC1QcmltYXJ5JywgJ2Zvcm0jQ29udGFjdCcpLnByZXYoJ3RkJykuaGlkZSgpO1xuXG4gICAgLy8gc2hpZnQgZGVtb2dyYXBoaWMgYWJvdmUgZXh0ZW5kZWQgZGVtb2dyYXBoaWNcbiAgICAkKCcuY3JtLWRlbW9ncmFwaGljcy1hY2NvcmRpb24nLCAnZm9ybSNDb250YWN0JykuaW5zZXJ0QWZ0ZXIoJCgnLmNybS1jb250YWN0RGV0YWlscy1hY2NvcmRpb24nKSk7XG5cbiAgICBpZiAoJCgndHIjUGhvbmVfQmxvY2tfMicsICdmb3JtI0NvbnRhY3QnKS5sZW5ndGggPCAxKSB7XG4gICAgICAkKCcjYWRkUGhvbmUnKS5jbGljaygpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgdGhlICNqcy11cGxvYWRlZC1maWxlIERJViBhbmRcbiAgICogY2xlYW4gaW5wdXRbdHlwZT1cImZpbGVcIl0gdmFsdWVcbiAgICovXG4gIGZ1bmN0aW9uIHJlbW92ZUZpbGUgKCkge1xuICAgIHZhciAkaW5wdXQgPSAkKCcjanMtdXBsb2FkZWQtZmlsZScpLnBhcmVudCgpLmZpbmQoJ2lucHV0W3R5cGU9XCJmaWxlXCJdJyk7XG5cbiAgICAkKCcjanMtdXBsb2FkZWQtZmlsZScpLnJlbW92ZSgpO1xuICAgICRpbnB1dC52YWwoJycpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1vdmVzIHRoZSBnaXZlbiBob21lIGxpbmsgcmlnaHQgdW5kZXIgdGhlIG1lbnUgaXRlbSBhbmQgZ2V0cyByaWRcbiAgICogb2YgdGhlIG9yaWdpbmFsIHN1YiBtZW51XG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSAkbWVudUl0ZW0gVGhlIGNvbnRleHQgd2hlcmUgdG8gZmluZCB0aGUgbGlua1xuICAgKiBAcGFyYW0ge29iamVjdH0gJGhvbWVMaW5rXG4gICAqL1xuICBmdW5jdGlvbiByZW1vdmVMb2dvU3ViTWVudUFuZEtlZXBPbmx5SG9tZUxpbmsgKCRtZW51SXRlbSwgJGhvbWVMaW5rKSB7XG4gICAgJG1lbnVJdGVtXG4gICAgICAub2ZmKCkgLy8gcmVtb3ZlcyBhbnkgaGFuZGxlciB0aGF0IHRoZSBvcmlnaW5hbCBpdGVtIGhhZFxuICAgICAgLmZpbmQoJyNjaXZpY3JtLWhvbWUnKVxuICAgICAgLmJlZm9yZSgkaG9tZUxpbmspXG4gICAgICAucmVtb3ZlKCk7XG4gIH1cblxuICAvKipcbiAgICogTW92ZXMgdGhlIFwiSW5saW5lIEN1c3RvbSBEYXRhXCIgZmllbGRzIHRvd2FyZHMgdGhlIHRvcCBvZiB0aGVcbiAgICogZWRpdCBjb250YWN0IGZvcm1cbiAgICovXG4gIGZ1bmN0aW9uIHJlcG9zaXRpb25JbmxpbmVDdXN0b21EYXRhRmllbGRzSW5FZGl0Q29udGFjdEZvcm0gKCkge1xuICAgIHZhciAkZmllbGRzID0gJCgnI0lubGluZV9DdXN0b21fRGF0YScpLmRldGFjaCgpO1xuXG4gICAgJGZpZWxkcy5maW5kKCcubGFiZWwnKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciAkbGFiZWxDZWxsID0gJCh0aGlzKTtcbiAgICAgIHZhciAkZmllbGRDZWxsID0gJGxhYmVsQ2VsbC5uZXh0KCk7XG4gICAgICB2YXIgJG5ld1RkID0gJCgnPHRkLz4nKTtcblxuICAgICAgJG5ld1RkLmFwcGVuZCgkbGFiZWxDZWxsLmZpbmQoJ2xhYmVsJykpO1xuICAgICAgJG5ld1RkLmFwcGVuZCgkKCc8YnIvPicpKTtcbiAgICAgICRuZXdUZC5hcHBlbmQoJGZpZWxkQ2VsbC5odG1sKCkpO1xuXG4gICAgICAkKCcjbmlja19uYW1lJykucGFyZW50KCkuYWZ0ZXIoJG5ld1RkKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNb3ZlcyB0aGUgc3BlY2lmaWVkIHNlbGVjdG9yIGVsZW1lbnQgdG8gdGhlIHBlcnNvbmFsIGRldGFpbHMgdGFiXG4gICAqXG4gICAqIEBwYXJhbSBzZWxlY3RvclxuICAgKi9cbiAgZnVuY3Rpb24gcmVwb3NpdGlvblBlcnNvbmFsRGV0YWlsc0Jsb2NrIChzZWxlY3Rvcikge1xuICAgICQoc2VsZWN0b3IpXG4gICAgICAucmVtb3ZlQ2xhc3MoJ2NybS1jb2xsYXBzaWJsZSBjb2xsYXBzZWQnKVxuICAgICAgLmFkZENsYXNzKCdjcm0tc3VtbWFyeS1ibG9jaycpXG4gICAgICAuYXBwZW5kVG8oJy5jb250YWN0VG9wQmFyIC5jb250YWN0Q2FyZExlZnQnKVxuICAgICAgLmZpbmQoJy5jb2xsYXBzaWJsZS10aXRsZScpLmhpZGUoKS5lbmQoKVxuICAgICAgLmZpbmQoJy5jcm0tc3VtbWFyeS1ibG9jaycpLnNob3coKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTd2FwcyB0aGUgQ2l2aUNSTSBsb2dvIHdpdGggdGhlIENpdmlIUiBsb2dvXG4gICAqIGFuZCB3cmFwcyBpdCBpbiBhIGBtZW51bWFpbi1pY29uYCBlbGVtZW50XG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSAkbWVudUl0ZW0gVGhlIGNvbnRleHQgd2hlcmUgdG8gZmluZCB0aGUgbG9nb1xuICAgKiBAcmV0dXJuIHRoZSB3cmFwcGVyIG9mIHRoZSBsb2dvXG4gICAqL1xuICBmdW5jdGlvbiBzd2FwQW5kV3JhcEFwcExvZ28gKCRtZW51SXRlbSkge1xuICAgIHZhciAkYXBwTG9nbyA9ICQoJy5jcm0tbG9nby1zbScsICRtZW51SXRlbSk7XG5cbiAgICByZXR1cm4gJGFwcExvZ29cbiAgICAgIC5hZGRDbGFzcygnY2hyX2xvZ28gY2hyX2xvZ28tLWRlZmF1bHQtY29sb3InKVxuICAgICAgLnJlbW92ZUNsYXNzKCdjcm0tbG9nby1zbScpXG4gICAgICAud3JhcCgnPHNwYW4gY2xhc3M9XCJtZW51bWFpbi1pY29uXCI+JylcbiAgICAgIC5wYXJlbnQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaXZpQ1JNIGJ5IGRlZmF1bHQgYXBwbGllcyBvbiBob3ZlciB0aGUgLmFjdGl2ZXRhcmdldCBjbGFzc1xuICAgKiBvbmx5IHRvIG1haW4gbWVudSBpdGVtcyB3aXRoIGEgc3VibWVudVxuICAgKlxuICAgKiBUaGlzIGZ1bmN0aW9ucyBtYWtlcyBzdXJlIHRoYXQgYW55IGl0ZW0gZ2V0cyB0aGUgY2xhc3MgYXBwbGllZCxcbiAgICogZXZlbiB0aG9zZSB3aXRoIGp1c3QgYSBkaXJlY3QgbGlua1xuICAgKi9cbiAgZnVuY3Rpb24gdG9nZ2xlQWN0aXZlQ2xhc3NPbkhvdmVyT25BbnlNYWluTWVudUl0ZW0gKCkge1xuICAgIHZhciBjbGFzc05hbWUgPSAnYWN0aXZldGFyZ2V0JztcblxuICAgICQoJy5tZW51bWFpbicpLm5vdCgnLmNybS1TZWxmX1NlcnZpY2VfUG9ydGFsJykuaG92ZXIoZnVuY3Rpb24gKCkge1xuICAgICAgJCh0aGlzKS5hZGRDbGFzcyhjbGFzc05hbWUpO1xuICAgIH0sIGZ1bmN0aW9uICgpIHtcbiAgICAgICQodGhpcykucmVtb3ZlQ2xhc3MoY2xhc3NOYW1lKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgdGhlIGFycm93IGZvciBtZW51IGl0ZW1zIHdpdGggc3ViLWl0ZW1zLCBhbmQgcmVwbGFjZXMgaXRcbiAgICogd2l0aCBhIGZvbnQgYXdlc29tZSBjYXJldFxuICAgKi9cbiAgZnVuY3Rpb24gdXNlRm9udEF3ZXNvbWVBcnJvd3NJblN1Yk1lbnVJdGVtcyAoKSB7XG4gICAgJCgnI3Jvb3QtbWVudS1kaXYgLm1lbnUtaXRlbS1hcnJvdycpLmVhY2goZnVuY3Rpb24gKCRlbGVtZW50KSB7XG4gICAgICB2YXIgJGFycm93ID0gJCh0aGlzKTtcblxuICAgICAgJGFycm93LmJlZm9yZSgnPGkgY2xhc3M9XCJmYSBmYS1jYXJldC1yaWdodCBtZW51LWl0ZW0tYXJyb3dcIj48L2k+Jyk7XG4gICAgICAkYXJyb3cucmVtb3ZlKCk7XG4gICAgfSk7XG4gIH1cbn0oQ1JNLiQsIENSTS5fKSk7XG4iLCIoZnVuY3Rpb24gKCQpIHtcbiAgJ3VzZSBzdHJpY3QnO1xuICB2YXIgTXV0YXRpb25PYnNlcnZlciA9IHdpbmRvdy5NdXRhdGlvbk9ic2VydmVyIHx8IHdpbmRvdy5XZWJLaXRNdXRhdGlvbk9ic2VydmVyIHx8IHdpbmRvdy5Nb3pNdXRhdGlvbk9ic2VydmVyO1xuXG4gIC8qXG4gIFRoaXMgcGx1Z2luIGNyZWF0ZXMgTXV0YXRpb25PYnNlcnZlciB3aGljaCBsaXN0ZW5zIHRvIGFsbCBjaGFuZ2VzIHRvIERPTSBOb2RlLlxuICBJZiBjaGFuZ2UgaGFzIGJlZW4gZG9uZSB0byBpdCdzIGF0dHJpYnV0ZXMgY2FsbGJhY2sgd2lsbCBiZSBjYWxsZWQuXG5cbiAgQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2sgLSB0byBiZSBjYWxsZWQgd2hlbiBhdHRyaWJ1dGVzIGNoYW5nZVxuICBAcmV0dXJucyB7QXJyYXl9IC0gbGlzdCBvZiBhbGwgb2JzZXJ2ZWQgZWxlbWVudHNcbiAgKi9cbiAgJC5mbi5hdHRyY2hhbmdlID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gICAgaWYgKE11dGF0aW9uT2JzZXJ2ZXIpIHtcbiAgICAgIHZhciBvcHRpb25zID0ge1xuICAgICAgICBzdWJ0cmVlOiBmYWxzZSxcbiAgICAgICAgYXR0cmlidXRlczogdHJ1ZVxuICAgICAgfTtcblxuICAgICAgdmFyIG9ic2VydmVyID0gbmV3IE11dGF0aW9uT2JzZXJ2ZXIoZnVuY3Rpb24gKG11dGF0aW9ucykge1xuICAgICAgICBtdXRhdGlvbnMuZm9yRWFjaChmdW5jdGlvbiAoZSkge1xuICAgICAgICAgIGNhbGxiYWNrLmNhbGwoZS50YXJnZXQsIGUpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgb2JzZXJ2ZXIub2JzZXJ2ZSh0aGlzLCBvcHRpb25zKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxufSkoQ1JNLiQpO1xuIiwiLyogZ2xvYmFscyBDUk0gKi9cblxuLyoqXG4gKiBIZWxwcyB0byBkaXNwbGF5IHBvcHVwIG1lbnVzIGluc2lkZSAjYm9vdHN0cmFwLXRoZW1lIGVsZW1lbnRzLCBzaW5jZSAucGFuZWwnc1xuICogYW5kIG90aGVyIEJvb3RzdHJhcCBlbGVtZW50cyBjbGFzaCB3aXRoIENpdmlDUk0gc3R5bGVzIHByb2R1Y2luZyB1bmRlc2lyZWRcbiAqIHJlc3VsdHMuXG4gKlxuICogSXQgYWxzbyBoZWxwcyB3aXRoIGV2ZW50IGJpbmRpbmdzLCBpbiBjYXNlIHRoZSBvcmlnaW5hbCBwb3B1cCBidXR0b24gd2FzXG4gKiByZW1vdmVkIGFuZCByZWNyZWF0ZWQsIGJ5IGZvcndhcmRpbmcgdGhlIGV2ZW50cyB0byB0aGUgb3JpZ2luYWwgc291cmNlLlxuICovXG4oZnVuY3Rpb24gKCQpIHtcbiAgJ3VzZSBzdHJpY3QnO1xuICB2YXIgJGJvZHkgPSAkKCdib2R5Jyk7XG5cbiAgJGJvZHkub24oJ2NsaWNrJywgJyNib290c3RyYXAtdGhlbWUgLmJ0bi1zbGlkZScsIGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgJHBvcHVwQ2xvbmU7XG4gICAgdmFyICRidXR0b24gPSAkKHRoaXMpO1xuICAgIHZhciAkcG9wdXAgPSAkYnV0dG9uLmNoaWxkcmVuKCd1bC5wYW5lbCcpO1xuXG4gICAgKGZ1bmN0aW9uIGluaXQgKCkge1xuICAgICAgY2xvc2VQb3B1cFBhbmVscygpO1xuICAgICAgY3JlYXRlUG9wdXBDbG9uZSgpO1xuICAgICAgb3BlblBvcHVwQ2xvbmUoKTtcbiAgICAgIG1hcENsb25lQ2xpY2tFdmVudHNUb09yaWdpbigpO1xuICAgICAgbGlzdGVuVG9Nb3VzZU91dEV2ZW50KCk7XG4gICAgfSkoKTtcblxuICAgIC8qKlxuICAgICAqIENsb3NlcyB0aGUgYW55IHBvcHVwIHBhbmVsIHRoYXQgaXMgY3VycmVudGx5IG9wZW4gYW5kIHJlbW92ZXMgdGhlXG4gICAgICogYC5jaXZpaHItcG9wdXAtb3BlbmAgY2xhc3MgZnJvbSB0aGUgYm9keS5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBjbG9zZVBvcHVwUGFuZWxzICgpIHtcbiAgICAgICQoJy5jaXZpaHItcG9wdXAnKS5yZW1vdmUoKTtcbiAgICAgICRib2R5LnJlbW92ZUNsYXNzKCdjaXZpaHItcG9wdXAtb3BlbicpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBjbG9uZSBvZiB0aGUgcG9wdXAgZWxlbWVudCBhbmQgYXBwZW5kcyBpdCB0byB0aGUgZG9jdW1lbnQgYm9keS5cbiAgICAgKiBUaGlzIHByZXZlbnRzIHRoZSBwb3B1cCB0byBiZSBoaWRkZW4gYnkgYW55IGBvdmVyZmxvdzogaGlkZGVuO2AgcnVsZS5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBjcmVhdGVQb3B1cENsb25lICgpIHtcbiAgICAgICRwb3B1cENsb25lID0gJHBvcHVwLmNsb25lKHRydWUpXG4gICAgICAgIC5hcHBlbmRUbygkYm9keSlcbiAgICAgICAgLmFkZENsYXNzKCdjaXZpaHItcG9wdXAnKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBMaXN0ZW5zIHRvIG1vdXNlIGV2ZW50cyBoYXBwZW5pbmcgb3V0c2lkZSB0aGUgb2YgdGhlIHBhbmVsIGluIG9yZGVyIHRvXG4gICAgICogY2xvc2UgaXQuIFRoZSB3YXkgdG8gZGV0ZWN0ZWQgbW91c2Ugb3V0IGlzIGJ5IGxpc3RlbmluZyB0byB0aGVcbiAgICAgKiAuYnRuLXNsaWRlLWFjdGl2ZSBjbGFzcyBjaGFuZ2UsIHdoaWNoIGlzIGFkZGVkIGFuZCByZW1vdmVkIGJ5IENpdmlDUk0uXG4gICAgICogdGhlIGRhdGEgKmF0dHJjaGFuZ2UtaXMtb24qIGlzIHNldCB0byB0cnVlIGluIG9yZGVyIHRvIGF2b2lkIGFkZGluZ1xuICAgICAqIG11bHRpcGxlIGxpc3RlbmVycyB0byB0aGUgc2FtZSBlbGVtZW50LlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGxpc3RlblRvTW91c2VPdXRFdmVudCAoKSB7XG4gICAgICAvLyBJZiBBdHRyQ2hhbmdlIGV2ZW50IGlzIGFscmVhZHkgbGlzdGVuZWQsIHRoZW4gc2tpcDpcbiAgICAgIGlmICgkYnV0dG9uLmRhdGEoJ2F0dHJjaGFuZ2UtaXMtb24nKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgICRidXR0b24uZGF0YSgnYXR0cmNoYW5nZS1pcy1vbicsIHRydWUpO1xuICAgICAgJGJ1dHRvbi5hdHRyY2hhbmdlKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLy8gSWYgYnV0dG9uIGlzIGFscmVhZHkgb3BlbiwgdGhlbiBza2lwOlxuICAgICAgICBpZiAoJGJ1dHRvbi5oYXNDbGFzcygnYnRuLXNsaWRlLWFjdGl2ZScpKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY2xvc2VQb3B1cFBhbmVscygpO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTWFwcyBjbGljayBldmVudHMgb24gdGhlIHBvcHVwIG9wdGlvbnMgYmFjayB0byB0aGVpciBvcmlnaW5hbCBzb3VyY2UuXG4gICAgICogVGhpcyBpcyBkb25lIGJlY2F1c2UgcG9wdXAgYWN0aW9ucyBhcmUgZXhlY3V0ZWQgYXMgZGVsZWdhdGVkIGV2ZW50cyBhbmRcbiAgICAgKiB0aGUgbGlzdGVuZXIgaXMgbm90IHRoZSAqYm9keSogZWxlbWVudC5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBtYXBDbG9uZUNsaWNrRXZlbnRzVG9PcmlnaW4gKCkge1xuICAgICAgJHBvcHVwQ2xvbmUuZmluZCgnYScpLmNsaWNrKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGFjdGlvbkluZGV4ID0gJCh0aGlzKS5wYXJlbnQoKS5pbmRleCgpO1xuXG4gICAgICAgICRwb3B1cC5maW5kKCdsaTpudGgoJyArIGFjdGlvbkluZGV4ICsgJykgYScpLmNsaWNrKCk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBPcGVucyB0aGUgcG9wdXAgcGFuZWwgY2xvbmVcbiAgICAgKiBhbmQgYWRkcyB0aGUgLmNpdmloci1wb3B1cC1vcGVuIGNsYXNzIHRvIHRoZSBib2R5XG4gICAgICovXG4gICAgZnVuY3Rpb24gb3BlblBvcHVwQ2xvbmUgKCkge1xuICAgICAgdmFyIGJ1dHRvbk9mZnNldCA9ICRidXR0b24ub2Zmc2V0KCk7XG5cbiAgICAgICRwb3B1cENsb25lLmNzcyh7XG4gICAgICAgIGxlZnQ6ICtidXR0b25PZmZzZXQubGVmdCAtICgkcG9wdXBDbG9uZS53aWR0aCgpIC0gJGJ1dHRvbi5vdXRlcldpZHRoKCkpLFxuICAgICAgICB0b3A6ICtidXR0b25PZmZzZXQudG9wICsgJGJ1dHRvbi5vdXRlckhlaWdodCgpXG4gICAgICB9KTtcbiAgICAgICRwb3B1cENsb25lLnNob3coKTtcbiAgICAgICRib2R5LmFkZENsYXNzKCdjaXZpaHItcG9wdXAtb3BlbicpO1xuICAgIH1cbiAgfSk7XG59KShDUk0uJCk7XG4iXX0= +//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImNvbnRhY3QuanMiLCJocnVpLmpzIiwiY2l2aWhyLXBvcHVwL2F0dHJjaGFuZ2UuanMiLCJjaXZpaHItcG9wdXAvY2l2aWhyLXBvcHVwLmpzIl0sIm5hbWVzIjpbIiQiLCJfIiwidXBkYXRlQ29udGFjdEhlYWRlclJvbGVzRGV0YWlscyIsInJvbGVzIiwiZGVwYXJ0bWVudHMiLCJsZW5ndGgiLCJodG1sIiwiam9pbiIsImRvY3VtZW50Iiwib24iLCJlIiwib25lIiwiJGZvcm0iLCJ0aGlzIiwiZmluZCIsImVhY2giLCIkbGFiZWwiLCJpZCIsImF0dHIiLCJ0ZXh0IiwiZGF0YSIsImNvbnRyYWN0IiwicmVtb3ZlQ2xhc3MiLCJwb3NpdGlvbiIsImxvY2F0aW9uIiwiYWRkQ2xhc3MiLCJDUk0iLCJpbnNlcnRGaWxlIiwiZmlsZU5hbWUiLCJmaWxlcyIsInJlbW92ZSIsInVuZGVmaW5lZCIsImFmdGVyIiwibmFtZSIsInJlbW92ZUZpbGUiLCJsaW5rTGFiZWxUb0RhdGVwaWNrZXJJbnB1dCIsIiRsaW5lIiwiJGlucHV0IiwicGFyZW50IiwidmFsIiwic2VsZWN0b3IiLCJ0YXJnZXQiLCJwYXJlbnRzIiwiaW5kZXhPZiIsImdldCIsImZvcm1OYW1lIiwicGFnZU5hbWUiLCJpbnNlcnRBZnRlciIsImhpZGUiLCJlbmQiLCJzaG93IiwiZGV0YWNoIiwiJGxhYmVsQ2VsbCIsIiRmaWVsZENlbGwiLCJuZXh0IiwiJG5ld1RkIiwiYXBwZW5kIiwiY2xvc2VzdCIsImluc2VydEJlZm9yZSIsInByZXYiLCJjbGljayIsIndpbmRvdyIsInNldFRpbWVvdXQiLCJBcnJheSIsInByb3RvdHlwZSIsImZvckVhY2giLCJjYWxsIiwicXVlcnlTZWxlY3RvckFsbCIsImVsZW1lbnQiLCJQcyIsImluaXRpYWxpemUiLCJjaGlsZHJlbiIsInJlYWR5IiwiJG1lbnVJdGVtIiwiJHdyYXBwZWRMb2dvIiwiJGN1c3RvbUhvbWVMaW5rIiwiJGFwcExvZ28iLCIkaG9tZUxpbmsiLCJjbGFzc05hbWUiLCJhamF4IiwiZGF0YVR5cGUiLCJzdWNjZXNzIiwibWVudU1hcmt1cCIsIndyYXBwZXJJZCIsIiRtZW51TWFya3VwIiwiJG1lbnVXcmFwcGVyIiwid3JhcCIsImZpcnN0Iiwid3JhcElubmVyIiwicHJlcGVuZCIsIm9mZiIsImJlZm9yZSIsIiRlbGVtZW50IiwiJGFycm93Iiwibm90IiwiaG92ZXIiLCJNdXRhdGlvbk9ic2VydmVyIiwiV2ViS2l0TXV0YXRpb25PYnNlcnZlciIsIk1vek11dGF0aW9uT2JzZXJ2ZXIiLCJmbiIsImF0dHJjaGFuZ2UiLCJjYWxsYmFjayIsIm9wdGlvbnMiLCJzdWJ0cmVlIiwiYXR0cmlidXRlcyIsIm9ic2VydmVyIiwibXV0YXRpb25zIiwib2JzZXJ2ZSIsIiRib2R5IiwiJHBvcHVwQ2xvbmUiLCJidXR0b25PZmZzZXQiLCIkYnV0dG9uIiwiJHBvcHVwIiwiY2xvc2VQb3B1cFBhbmVscyIsImNsb25lIiwiYXBwZW5kVG8iLCJvZmZzZXQiLCJjc3MiLCJsZWZ0Iiwid2lkdGgiLCJvdXRlcldpZHRoIiwidG9wIiwib3V0ZXJIZWlnaHQiLCJhY3Rpb25JbmRleCIsImluZGV4IiwiaGFzQ2xhc3MiXSwibWFwcGluZ3MiOiJDQUFDLFNBQVVBLEVBQUdDLEdBdURaLFNBQVNDLEVBQWlDQyxHQUNwQ0EsR0FBU0EsRUFBTUMsYUFBZUQsRUFBTUMsWUFBWUMsT0FBUyxFQUMzREwsRUFBRSxtQ0FBbUNNLEtBQUssZ0NBQWtDSCxFQUFNQyxZQUFZRyxLQUFLLE9BRW5HUCxFQUFFLG1DQUFtQ00sS0FBSyxJQTFEOUNOLEVBQUVRLFVBQ0NDLEdBQUcsVUFBVyxTQUFVQyxHQUN2QlYsRUFBRSxvQkFBb0JXLElBQUkscUJBQXNCLFdBQzlDLElBQUlDLEVBQVFaLEVBQUVhLE1BQU1DLEtBQUssUUFFSixJQUFqQkYsRUFBTVAsUUFDUk8sRUFBTUUsS0FBSyxTQUFTQyxLQUFLLFdBQ3ZCLElBQUlDLEVBQVNoQixFQUFFYSxNQUNYSSxFQUFLRCxFQUFPRSxLQUFLLE9BQ3JCbEIsRUFB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R0FBRyxRQUFTLDhCQUErQixXQUMvQyxJQUFJb0csRUF5RUVDLEVBeEVGQyxFQUFVL0csRUFBRWEsTUFDWm1HLEVBQVNELEVBQVF4QyxTQUFTLFlBYzlCLFNBQVMwQyxJQUNQakgsRUFBRSxpQkFBaUI4QixTQUNuQjhFLEVBQU10RixZQUFZLHFCQWJsQjJGLElBcUJBSixFQUFjRyxFQUFPRSxPQUFNLEdBQ3hCQyxTQUFTUCxHQUNUbkYsU0FBUyxnQkE2Q1JxRixFQUFlQyxFQUFRSyxTQUUzQlAsRUFBWVEsS0FDVkMsTUFBT1IsRUFBYVEsTUFBUVQsRUFBWVUsUUFBVVIsRUFBUVMsY0FDMURDLEtBQU1YLEVBQWFXLElBQU1WLEVBQVFXLGdCQUVuQ2IsRUFBWTNELE9BQ1owRCxFQUFNbkYsU0FBUyxxQkFuQmZvRixFQUFZL0YsS0FBSyxLQUFLOEMsTUFBTSxXQUMxQixJQUFJK0QsRUFBYzNILEVBQUVhLE1BQU15QixTQUFTc0YsUUFFbkNaLEVBQU9sRyxLQUFLLFVBQVk2RyxFQUFjLE9BQU8vRCxVQXhCM0NtRCxFQUFRM0YsS0FBSyxzQkFJakIyRixFQUFRM0YsS0FBSyxvQkFBb0IsR0FDakMyRixFQUFRWCxXQUFXLFdBRWJXLEVBQVFjLFNBQVMscUJBSXJCWixTQXhEUixDQXdGR3ZGLElBQUkxQiIsImZpbGUiOiJocnVpLm1pbi5qcyIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiAoJCwgXykge1xuICAkKGRvY3VtZW50KVxuICAgIC5vbignY3JtTG9hZCcsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAkKCcuY3JtLWlubGluZS1lZGl0Jykub25lKCdET01TdWJ0cmVlTW9kaWZpZWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciAkZm9ybSA9ICQodGhpcykuZmluZCgnZm9ybScpO1xuXG4gICAgICAgIGlmICgkZm9ybS5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICAkZm9ybS5maW5kKCdsYWJlbCcpLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyICRsYWJlbCA9ICQodGhpcyk7XG4gICAgICAgICAgICB2YXIgaWQgPSAkbGFiZWwuYXR0cignZm9yJyk7XG4gICAgICAgICAgICAkKCcjJyArIGlkKS5hdHRyKCdwbGFjZWhvbGRlcicsICRsYWJlbC50ZXh0KCkpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KVxuICAgIC5vbigndXBkYXRlQ29udGFjdEhlYWRlcicsIGZ1bmN0aW9uIChlLCBkYXRhKSB7XG4gICAgICBpZiAodHlwZW9mIGRhdGEuY29udHJhY3QgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIHVwZGF0ZUNvbnRhY3RIZWFkZXJDb250cmFjdERldGFpbHMoZGF0YS5jb250cmFjdCk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0eXBlb2YgZGF0YS5yb2xlcyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgdXBkYXRlQ29udGFjdEhlYWRlclJvbGVzRGV0YWlscyhkYXRhLnJvbGVzKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAvKipcbiAgICogVXBkYXRlcyB0aGUgY29udGFjdCBoZWFkZXIgd2l0aCB0aGUgZ2l2ZW4gY29udHJhY3QgZGV0YWlsc1xuICAgKlxuICAgKiBAcGFyYW0gIHtvYmplY3R9IGNvbnRyYWN0XG4gICAqL1xuICBmdW5jdGlvbiB1cGRhdGVDb250YWN0SGVhZGVyQ29udHJhY3REZXRhaWxzIChjb250cmFjdCkge1xuICAgIGlmIChjb250cmFjdCkge1xuICAgICAgJCgnLmNybS1zdW1tYXJ5LWNvbnRhY3RuYW1lLWJsb2NrJykucmVtb3ZlQ2xhc3MoJ2NybS1zdW1tYXJ5LWNvbnRhY3RuYW1lLWJsb2NrLXdpdGhvdXQtY29udHJhY3QnKTtcblxuICAgICAgaWYgKGNvbnRyYWN0LnBvc2l0aW9uKSB7XG4gICAgICAgICQoJy5jcm0tY29udGFjdC1kZXRhaWwtcG9zaXRpb24nKS5odG1sKCc8c3Ryb25nPlBvc2l0aW9uOjwvc3Ryb25nPiAnICsgY29udHJhY3QucG9zaXRpb24pO1xuICAgICAgfVxuXG4gICAgICBpZiAoY29udHJhY3QubG9jYXRpb24pIHtcbiAgICAgICAgJCgnLmNybS1jb250YWN0LWRldGFpbC1sb2NhdGlvbicpLmh0bWwoJzxzdHJvbmc+Tm9ybWFsIHBsYWNlIG9mIHdvcms6PC9zdHJvbmc+ICcgKyBjb250cmFjdC5sb2NhdGlvbik7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgICQoJy5jcm0tc3VtbWFyeS1jb250YWN0bmFtZS1ibG9jaycpLmFkZENsYXNzKCdjcm0tc3VtbWFyeS1jb250YWN0bmFtZS1ibG9jay13aXRob3V0LWNvbnRyYWN0Jyk7XG4gICAgICAkKCcuY3JtLWNvbnRhY3QtZGV0YWlsLXBvc2l0aW9uJykuaHRtbCgnJyk7XG4gICAgICAkKCcuY3JtLWNvbnRhY3QtZGV0YWlsLWxvY2F0aW9uJykuaHRtbCgnJyk7XG5cbiAgICAgIHVwZGF0ZUNvbnRhY3RIZWFkZXJSb2xlc0RldGFpbHMobnVsbCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgdGhlIGNvbnRhY3QgaGVhZGVyIHdpdGggdGhlIGdpdmVuIHJvbGVzIGRldGFpbHNcbiAgICpcbiAgICogQHBhcmFtICB7b2JqZWN0fSBjb250cmFjdFxuICAgKi9cbiAgZnVuY3Rpb24gdXBkYXRlQ29udGFjdEhlYWRlclJvbGVzRGV0YWlscyAocm9sZXMpIHtcbiAgICBpZiAocm9sZXMgJiYgcm9sZXMuZGVwYXJ0bWVudHMgJiYgcm9sZXMuZGVwYXJ0bWVudHMubGVuZ3RoID4gMCkge1xuICAgICAgJCgnLmNybS1jb250YWN0LWRldGFpbC1kZXBhcnRtZW50cycpLmh0bWwoJzxzdHJvbmc+RGVwYXJ0bWVudDo8L3N0cm9uZz4gJyArIHJvbGVzLmRlcGFydG1lbnRzLmpvaW4oJywgJykpO1xuICAgIH0gZWxzZSB7XG4gICAgICAkKCcuY3JtLWNvbnRhY3QtZGV0YWlsLWRlcGFydG1lbnRzJykuaHRtbCgnJyk7XG4gICAgfVxuICB9XG59KENSTS4kLCBDUk0uXykpO1xuIiwiLyogZ2xvYmFsIFBzICovXG5cbi8vIENvcHlyaWdodCBDaXZpQ1JNIExMQyAyMDEzLiBTZWUgaHR0cDovL2Npdmljcm0ub3JnL2xpY2Vuc2luZ1xuKGZ1bmN0aW9uICgkLCBfKSB7XG4gICQoZG9jdW1lbnQpXG4gICAgLm9uKCdjcm1Mb2FkJywgZnVuY3Rpb24gKGUpIHtcbiAgICAgIGFkZFVwbG9hZEZpbGVMaXN0ZW5lcihcImlucHV0W3R5cGU9J2ZpbGUnXVwiKTtcbiAgICAgIGFtZW5kVmFjYW5jeUZvcm0oKTtcbiAgICAgIGFtZW5kQ29udGFjdFBhZ2VBbmRGb3JtKGUpO1xuICAgICAgYXBwbHlNaXNjQ2hhbmdlcygpO1xuICAgICAgY2hhbmdlQ29udGFjdFNvdXJjZUZpZWxkSGVscFRleHQoKTtcbiAgICB9KVxuICAgIC5yZWFkeShmdW5jdGlvbiAoKSB7XG4gICAgICBhZGRVc2VyTWVudVRvTWFpbk1lbnUoKTtcbiAgICAgIGFtZW5kQXBwTG9nb01lbnVJdGVtKCk7XG4gICAgICBhbWVuZEFwcGxpY2F0aW9uRm9ybSgpO1xuICAgICAgdXNlRm9udEF3ZXNvbWVBcnJvd3NJblN1Yk1lbnVJdGVtcygpO1xuICAgICAgdG9nZ2xlQWN0aXZlQ2xhc3NPbkhvdmVyT25BbnlNYWluTWVudUl0ZW0oKTtcbiAgICB9KTtcblxuICAvKipcbiAgICogQ3VzdG9taXplcyB0aGUgYXBwIGxvZ28gbWVudSBpdGVtLCBzd2l0Y2hpbmcgZnJvbSB0aGUgQ2l2aUNSTSBsb2dvXG4gICAqIHRvIHRoZSBDaXZpSFIgbG9nbywgYW5kIG1ha2luZyB0aGUgaXRlbSBhIGRpcmVjdCBsaW5rIGluc3RlYWQgb2YgYVxuICAgKiB0b2dnbGUgZm9yIGEgc3ViIG1lbnUgZHJvcGRvd25cbiAgICovXG4gIGZ1bmN0aW9uIGFtZW5kQXBwTG9nb01lbnVJdGVtICgpIHtcbiAgICB2YXIgJG1lbnVJdGVtID0gJCgnLmNybS1saW5rLWhvbWUnKTtcbiAgICB2YXIgJHdyYXBwZWRMb2dvID0gc3dhcEFuZFdyYXBBcHBMb2dvKCRtZW51SXRlbSk7XG4gICAgdmFyICRjdXN0b21Ib21lTGluayA9IGN1c3RvbWl6ZUhvbWVMaW5rSW5Mb2dvTWVudUl0ZW0oJG1lbnVJdGVtLCAkd3JhcHBlZExvZ28pO1xuXG4gICAgcmVtb3ZlTG9nb1N1Yk1lbnVBbmRLZWVwT25seUhvbWVMaW5rKCRtZW51SXRlbSwgJGN1c3RvbUhvbWVMaW5rKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIHRoZSB1c2VyIG1lbnUgYnkgZmV0Y2hpbmcgaXQgZnJvbSB0aGUgaHJjb3JlIGV4dGVuc2lvblxuICAgKi9cbiAgZnVuY3Rpb24gYWRkVXNlck1lbnVUb01haW5NZW51ICgpIHtcbiAgICAkLmFqYXgoJy9jaXZpY3JtL2hyY29yZS91c2VybWVudT9zbmlwcGV0PTQnLCB7XG4gICAgICBkYXRhVHlwZTogJ2h0bWwnLFxuICAgICAgc3VjY2VzczogZnVuY3Rpb24gKG1lbnVNYXJrdXApIHtcbiAgICAgICAgaW5qZWN0VXNlck1lbnVJbkFNYWluTWVudVdyYXBwZXIobWVudU1hcmt1cCwgJ2Npdmloci1tZW51Jyk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGFuIGV2ZW50IGxpc3RlbmVyIG9uIGlucHV0W3R5cGU9XCJmaWxlXCJdXG4gICAqIEBwYXJhbSB7alF1ZXJ5IE9iamVjdH0gc2VsZWN0b3IgW3NlbGVjdG9yIGZyb20gaW5wdXQgZmlsZV1cbiAgICovXG4gIGZ1bmN0aW9uIGFkZFVwbG9hZEZpbGVMaXN0ZW5lciAoc2VsZWN0b3IpIHtcbiAgICBpZiAoJChzZWxlY3RvcikubGVuZ3RoID09PSAxKSB7XG4gICAgICAkKHNlbGVjdG9yKS5vbignY2hhbmdlJywgaW5zZXJ0RmlsZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFtZW5kcyB0aGUgYXBwbGljYXRpb24gZm9ybVxuICAgKi9cbiAgZnVuY3Rpb24gYW1lbmRBcHBsaWNhdGlvbkZvcm0gKCkge1xuICAgICQoJy5DUk1fSFJSZWNydWl0bWVudF9Gb3JtX0FwcGxpY2F0aW9uJykuYWRkQ2xhc3MoJ2NybS1mb3JtLWJsb2NrJyk7XG4gICAgJCgnLkNSTV9IUlJlY3J1aXRtZW50X0Zvcm1fQXBwbGljYXRpb24gLmNybS1wcm9maWxlLW5hbWUtYXBwbGljYXRpb25fcHJvZmlsZScpLmFkZENsYXNzKCdmb3JtLWxheW91dC1jb21wcmVzc2VkJyk7XG4gIH1cblxuICAvKipcbiAgICogQW1lbmRzIHRoZSBjb250YWN0IHBhZ2UgYW5kIHRoZSBjb250YWN0IGZvcm1cbiAgICovXG4gIGZ1bmN0aW9uIGFtZW5kQ29udGFjdFBhZ2VBbmRGb3JtIChlKSB7XG4gICAgaWYgKENSTS5mb3JtTmFtZSA9PT0gJ2NvbnRhY3RGb3JtJyB8fCBDUk0ucGFnZU5hbWUgPT09ICd2aWV3U3VtbWFyeScpIHtcbiAgICAgIC8vIFJlbmFtZSBcIlN1bW1hcnlcIiB0YWIgdG8gXCJQZXJzb25hbCBEZXRhaWxzXCJcbiAgICAgIC8vIEhhY2sgdG8gY2hlY2sgY29udGFjdCB0eXBlIC0gVGhpcyBmaWVsZCBvbmx5IGFwcGVhcnMgZm9yIGluZGl2aWR1YWxzXG4gICAgICBpZiAoJCgnLmNybS1jb250YWN0LWpvYl90aXRsZScsICcuY3JtLXN1bW1hcnktY29udGFjdGluZm8tYmxvY2snKS5sZW5ndGgpIHtcbiAgICAgICAgJCgnLmNybS1jb250YWN0LXRhYnMtbGlzdCAjdGFiX3N1bW1hcnkgYScsIGUudGFyZ2V0KS50ZXh0KCdQZXJzb25hbCBEZXRhaWxzJyk7XG4gICAgICB9XG5cbiAgICAgIG1hbmlwdWxhdGVET01PZklubGluZUN1c3RvbURhdGEoZS50YXJnZXQpO1xuICAgICAgbWlzY0NvbnRhY3RQYWdlQ2hhbmdlcyhlLnRhcmdldCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFtZW5kcyB0aGUgdmFjYW5jeSBmb3JtXG4gICAqL1xuICBmdW5jdGlvbiBhbWVuZFZhY2FuY3lGb3JtICgpIHtcbiAgICBpZiAoJCgnLkNSTV9IUlJlY3J1aXRtZW50X0Zvcm1fSFJWYWNhbmN5JykubGVuZ3RoID09PSAxKSB7XG4gICAgICBsaW5rTGFiZWxUb0RhdGVwaWNrZXJJbnB1dCgkKCdsYWJlbFtmb3I9XCJzdGFydF9kYXRlXCJdJykucGFyZW50cygndHInKSk7XG4gICAgICBsaW5rTGFiZWxUb0RhdGVwaWNrZXJJbnB1dCgkKCdsYWJlbFtmb3I9XCJlbmRfZGF0ZVwiXScpLnBhcmVudHMoJ3RyJykpO1xuXG4gICAgICAvLyBBZGQgYSBjbGFzcyB0byBpZGVudGlmeSB0aGUgZm9ybSAnTmV3IFZhY2FuY3kgVGVtcGxhdGUnXG4gICAgICBpZiAoJCgnW25hbWU9XCJlbnRyeVVSTFwiXScpLnZhbCgpLmluZGV4T2YoJzt0ZW1wbGF0ZT0xJykgPiAtMSkge1xuICAgICAgICAkKCQoJy5DUk1fSFJSZWNydWl0bWVudF9Gb3JtX0hSVmFjYW5jeSB0Ym9keScpLmdldCgwKSkuYWRkQ2xhc3MoJ0NSTV9IUlJlY3J1aXRtZW50X0Zvcm1fSFJWYWNhbmN5X1RlbXBsYXRlJyk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFwcGxpZXMgbWlzY2VsbGFuZW91cyBVSSBjaGFuZ2VzXG4gICAqL1xuICBmdW5jdGlvbiBhcHBseU1pc2NDaGFuZ2VzICgpIHtcbiAgICAkKCcjYWN0aXZpdHlDdXN0b21EYXRhJykuYXR0cignY29sc3BhbicsIDMpO1xuICAgICQoJyNjcm0tYWN0aXZpdHktdmlldy10YWJsZSAuY3JtLWNhc2UtYWN0aXZpdHktdmlldy1DbGllbnQgLmxhYmVsJykuaHRtbCgnQ29udGFjdCcpO1xuICAgICQoJ3NwYW4uY3JtLWZyb3plbi1maWVsZCcsICcuY3JtLXByb2ZpbGUtbmFtZS1ocmlkZW50X3RhYicpLmNsb3Nlc3QoJ2RpdicpLnBhcmVudCgnZGl2JykuaGlkZSgpO1xuXG4gICAgJCgnLmNybS1hY2NvcmRpb24taGVhZGVyLmNybS1tYXN0ZXItYWNjb3JkaW9uLWhlYWRlcicpLm9uKCdjbGljaycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgQXJyYXkucHJvdG90eXBlLmZvckVhY2guY2FsbChkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcubGlzdGluZy1ib3gnKSwgZnVuY3Rpb24gKGVsZW1lbnQpIHtcbiAgICAgICAgICBQcy5pbml0aWFsaXplKGVsZW1lbnQpO1xuICAgICAgICB9KTtcbiAgICAgIH0sIDApO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENoYW5nZXMgb2Ygc29yY2UgaGVscCB0ZXh0XG4gICAqL1xuICBmdW5jdGlvbiBjaGFuZ2VDb250YWN0U291cmNlRmllbGRIZWxwVGV4dCAoKSB7XG4gICAgJCgnSU5QVVQjY29udGFjdF9zb3VyY2UnKS5wYXJlbnQoJ3RkJykuY2hpbGRyZW4oJ2EnKS5jbGljayhmdW5jdGlvbiAoKSB7XG4gICAgICAkKCcjY3JtLW5vdGlmaWNhdGlvbi1jb250YWluZXIgLmNybS1oZWxwIC5ub3RpZnktY29udGVudCcpLnJlbW92ZSgpO1xuXG4gICAgICBpZiAoJCgnI2NybS1ub3RpZmljYXRpb24tY29udGFpbmVyIC5jcm0taGVscCBwJykubGVuZ3RoKSB7XG4gICAgICAgICQoJyNjcm0tbm90aWZpY2F0aW9uLWNvbnRhaW5lciAuY3JtLWhlbHAgcCcpLnJlbW92ZSgpO1xuICAgICAgfVxuXG4gICAgICAkKCcjY3JtLW5vdGlmaWNhdGlvbi1jb250YWluZXIgLmNybS1oZWxwJykuYXBwZW5kKCc8cD5Tb3VyY2UgaXMgYSB1c2VmdWwgZmllbGQgd2hlcmUgZGF0YSBoYXMgYmVlbiBtaWdyYXRlZCB0byBDaXZpSFIgZnJvbSBvbmUgb3IgYSBudW1iZXIgb2Ygb3RoZXIgbGVnYWN5IHN5c3RlbXMuIFRoZSBTb3VyY2UgZmllbGQgd2lsbCBpbmRpY2F0ZSB3aGljaCBsZWdhY3kgc3lzdGVtIHRoZSBjb250YWN0IGhhcyBjb21lIGZyb20uPC9wPicpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmRzIHRoZSBvcmlnaW5hbCBsaW5rIHRvIHRoZSBob21lcGFnZSwgY2hhbmdlcyB0aGUgdGV4dCwgd3JhcHMgaXQgaW4gYVxuICAgKiBgbWVudW1haW4tbGFiZWxgIGVsZW1lbnQgYW5kIHByZXBlbmRzIGludGVybmFsbHkgdGhlIGdpdmVuIGFwcCBsb2dvXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSAkbWVudUl0ZW0gVGhlIGNvbnRleHQgd2hlcmUgdG8gZmluZCB0aGUgbGlua1xuICAgKiBAcGFyYW0ge29iamVjdH0gJGFwcExvZ29cbiAgICogQHJldHVybiB0aGUgY3VzdG9taXplZCBob21lIGxpbmtcbiAgICovXG4gIGZ1bmN0aW9uIGN1c3RvbWl6ZUhvbWVMaW5rSW5Mb2dvTWVudUl0ZW0gKCRtZW51SXRlbSwgJGFwcExvZ28pIHtcbiAgICB2YXIgJGhvbWVMaW5rID0gJCgnbGkgPiBhJywgJG1lbnVJdGVtKS5maXJzdCgpO1xuXG4gICAgcmV0dXJuICRob21lTGlua1xuICAgICAgLnRleHQoJ0hvbWUnKVxuICAgICAgLndyYXBJbm5lcignPHNwYW4gY2xhc3M9XCJtZW51bWFpbi1sYWJlbFwiPicpXG4gICAgICAucHJlcGVuZCgkYXBwTG9nbyk7XG4gIH1cblxuICAvKipcbiAgICogSW5qZWN0cyB0aGUgZ2l2ZW4gbWFya3VwIGluIGEgbWVudSB3cmFwcGVyIHdpdGggdGhlIGdpdmVuIGlkXG4gICAqIGNyZWF0ZWQgdG8gY29udGFpbiBib3RoIHRoZSBvcmlnaW5hbCBtZW51IGFuZCB0aGUgdXNlciBvbmVcbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1lbnVNYXJrdXBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHdyYXBwZXJJZFxuICAgKi9cbiAgZnVuY3Rpb24gaW5qZWN0VXNlck1lbnVJbkFNYWluTWVudVdyYXBwZXIgKG1lbnVNYXJrdXAsIHdyYXBwZXJJZCkge1xuICAgIHZhciAkbWVudU1hcmt1cCA9ICQobWVudU1hcmt1cCk7XG4gICAgdmFyICRtZW51V3JhcHBlciA9ICQoJzxkaXY+Jyk7XG5cbiAgICAkbWVudVdyYXBwZXIuYXR0cignaWQnLCB3cmFwcGVySWQpO1xuICAgICRtZW51V3JhcHBlci5hcHBlbmQoJCgnI2Npdmljcm0tbWVudScpKTtcbiAgICAkbWVudVdyYXBwZXIuYXBwZW5kKCRtZW51TWFya3VwKTtcbiAgICAkbWVudVdyYXBwZXIuaW5zZXJ0QWZ0ZXIoJyNwYWdlJyk7XG4gIH1cblxuICAvKipcbiAgICogSW5zZXJ0IGEgRE9NIG5vZGUgYWZ0ZXIgaW5wdXRbdHlwZT1cImZpbGVcIl1cbiAgICogd2l0aCB0aGUgZmlsZW5hbWVcbiAgICovXG4gIGZ1bmN0aW9uIGluc2VydEZpbGUgKCkge1xuICAgIHZhciBmaWxlTmFtZSA9ICQodGhpcylbMF0uZmlsZXNbMF07XG5cbiAgICAkKCcjanMtdXBsb2FkZWQtZmlsZScpLnJlbW92ZSgpO1xuICAgIGlmIChmaWxlTmFtZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAkKHRoaXMpLmFmdGVyKCc8c3BhbiBpZD1cImpzLXVwbG9hZGVkLWZpbGVcIiBjbGFzcz1cInVwbG9hZGVkLWZpbGVcIj4nICsgZmlsZU5hbWUubmFtZSArICcgPHNwYW4gY2xhc3M9XCJ1cGxvYWRlZC1maWxlLWljb24tdHJhc2hcIj48aSBjbGFzcz1cImZhIGZhLXRyYXNoLW9cIj48L2k+IFJlbW92ZTwvc3Bhbj4nKTtcblxuICAgICAgJCgnLnVwbG9hZGVkLWZpbGUtaWNvbi10cmFzaCcpLm9uKCdjbGljaycsIHJlbW92ZUZpbGUpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGUgbGFiZWwgJ2ZvcicgYXR0ciB0byB3b3JrcyB3aXRoIHRoZSBkYXRlcGlja2VyXG4gICAqXG4gICAqIEBwYXJhbSAge2pRdWVyeSBvYmplY3R9ICRsaW5lIFtkYXRlcGlja2VyJ3MgbGluZSBwYXJlbnRdXG4gICAqL1xuICBmdW5jdGlvbiBsaW5rTGFiZWxUb0RhdGVwaWNrZXJJbnB1dCAoJGxpbmUpIHtcbiAgICAkbGluZS5maW5kKCdsYWJlbCcpLmF0dHIoJ2ZvcicsICRsaW5lLmZpbmQoJy5jcm0tZm9ybS1kYXRlJykuYXR0cignaWQnKSk7XG4gIH1cblxuICAvKipcbiAgICogTWFuaXB1bGF0ZXMsIGF0IHRoZSBET00gbGV2ZWwsIHRoZSBibG9ja3MvZmllbGRzIGJlbG9uZ2luZyB0byB0aGVcbiAgICogSW5saW5lIEN1c3RvbSBEYXRhIGN1c3RvbSBmaWVsZHMgc2V0XG4gICAqL1xuICBmdW5jdGlvbiBtYW5pcHVsYXRlRE9NT2ZJbmxpbmVDdXN0b21EYXRhICgpIHtcbiAgICBpZiAoJCgnLklubGluZV9DdXN0b21fRGF0YScpLmxlbmd0aCkge1xuICAgICAgcmVwb3NpdGlvbklubGluZUN1c3RvbURhdGFCbG9ja0luUGVyc29uYWxEZXRhaWxzVGFiKCk7XG4gICAgfVxuXG4gICAgaWYgKCQoJyNjdXN0b21GaWVsZHMnKS5sZW5ndGggPCAxKSB7XG4gICAgICByZXBvc2l0aW9uSW5saW5lQ3VzdG9tRGF0YUZpZWxkc0luRWRpdENvbnRhY3RGb3JtKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIE1pc2MgY2hhbmdlcyB0byB0aGUgcGFnZSAoaGlkaW5nIGVsZW1lbnRzLCBpbnNlcnRpbmcgbmV3IG9uZXMsIGV0YylcbiAgICovXG4gIGZ1bmN0aW9uIG1pc2NDb250YWN0UGFnZUNoYW5nZXMgKHRhcmdldCkge1xuICAgIC8vIEhpZGUgY3VycmVudCBlbXBsb3llciBhbmQgam9iIHRpdGxlXG4gICAgLy8gQ29udGFjdCBzdW1tYXJ5IHNjcmVlbjpcbiAgICAkKCdkaXYuY3JtLWNvbnRhY3QtY3VycmVudF9lbXBsb3llciwgZGl2LmNybS1jb250YWN0LWpvYl90aXRsZScsICcuY3JtLXN1bW1hcnktY29udGFjdGluZm8tYmxvY2snKS5wYXJlbnQoJ2Rpdi5jcm0tc3VtbWFyeS1yb3cnKS5oaWRlKCk7XG4gICAgLy8gSW5saW5lIGVkaXQgZm9ybVxuICAgICQoJ2Zvcm0jQ29udGFjdEluZm8gaW5wdXQjZW1wbG95ZXJfaWQsIGZvcm0jQ29udGFjdEluZm8gaW5wdXQjam9iX3RpdGxlJywgdGFyZ2V0KS5jbG9zZXN0KCdkaXYuY3JtLXN1bW1hcnktcm93JykuaGlkZSgpO1xuICAgIC8vIENvbnRhY3QgZWRpdCBzY3JlZW5cbiAgICAkKCdpbnB1dCNlbXBsb3llcl9pZCwgaW5wdXQjam9iX3RpdGxlJywgJ2Zvcm0jQ29udGFjdCcpLnBhcmVudCgndGQnKS5oaWRlKCk7XG5cbiAgICAvKiBDaGFuZ2VzIG9uIEFkZCBJbmRpdmlkdWFsIHBhZ2VzIGFuZCBQZXJzb25hbCBkZXRhaWxzIHRhYiBmb3IgSFItMzU4ICovXG4gICAgLy8gTW92ZSBKb2Igc3VtbWFyeSB0byB0b3BcbiAgICAkKCcuSFJKb2JDb250cmFjdF9TdW1tYXJ5JywgdGFyZ2V0KS5pbnNlcnRCZWZvcmUoJCgnLmNybS1zdW1tYXJ5LWNvbnRhY3RpbmZvLWJsb2NrJykpO1xuICAgIC8vIGNoYW5nZXMgb2YgZW1haWwgYmxvY2ssIHJlbW92ZSBidWxrbWFpbCBhbmQgb25ob2xkXG4gICAgJCgnZGl2LmVtYWlsLXNpZ25hdHVyZSwgdGQjRW1haWwtQnVsa21haWwtaHRtbCcsICdmb3JtI0NvbnRhY3QnKS5oaWRlKCk7XG4gICAgJCgnI0VtYWlsLVByaW1hcnknLCAnZm9ybSNDb250YWN0JykucHJldigndGQnKS5wcmV2KCd0ZCcpLmhpZGUoKTtcbiAgICAkKCd0ZCNFbWFpbC1CdWxrbWFpbC1odG1sLCAjRW1haWwtUHJpbWFyeScsICdmb3JtI0NvbnRhY3QnKS5wcmV2KCd0ZCcpLmhpZGUoKTtcblxuICAgIC8vIHNoaWZ0IGRlbW9ncmFwaGljIGFib3ZlIGV4dGVuZGVkIGRlbW9ncmFwaGljXG4gICAgJCgnLmNybS1kZW1vZ3JhcGhpY3MtYWNjb3JkaW9uJywgJ2Zvcm0jQ29udGFjdCcpLmluc2VydEFmdGVyKCQoJy5jcm0tY29udGFjdERldGFpbHMtYWNjb3JkaW9uJykpO1xuXG4gICAgaWYgKCQoJ3RyI1Bob25lX0Jsb2NrXzInLCAnZm9ybSNDb250YWN0JykubGVuZ3RoIDwgMSkge1xuICAgICAgJCgnI2FkZFBob25lJykuY2xpY2soKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIHRoZSAjanMtdXBsb2FkZWQtZmlsZSBESVYgYW5kXG4gICAqIGNsZWFuIGlucHV0W3R5cGU9XCJmaWxlXCJdIHZhbHVlXG4gICAqL1xuICBmdW5jdGlvbiByZW1vdmVGaWxlICgpIHtcbiAgICB2YXIgJGlucHV0ID0gJCgnI2pzLXVwbG9hZGVkLWZpbGUnKS5wYXJlbnQoKS5maW5kKCdpbnB1dFt0eXBlPVwiZmlsZVwiXScpO1xuXG4gICAgJCgnI2pzLXVwbG9hZGVkLWZpbGUnKS5yZW1vdmUoKTtcbiAgICAkaW5wdXQudmFsKCcnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNb3ZlcyB0aGUgZ2l2ZW4gaG9tZSBsaW5rIHJpZ2h0IHVuZGVyIHRoZSBtZW51IGl0ZW0gYW5kIGdldHMgcmlkXG4gICAqIG9mIHRoZSBvcmlnaW5hbCBzdWIgbWVudVxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gJG1lbnVJdGVtIFRoZSBjb250ZXh0IHdoZXJlIHRvIGZpbmQgdGhlIGxpbmtcbiAgICogQHBhcmFtIHtvYmplY3R9ICRob21lTGlua1xuICAgKi9cbiAgZnVuY3Rpb24gcmVtb3ZlTG9nb1N1Yk1lbnVBbmRLZWVwT25seUhvbWVMaW5rICgkbWVudUl0ZW0sICRob21lTGluaykge1xuICAgICRtZW51SXRlbVxuICAgICAgLm9mZigpIC8vIHJlbW92ZXMgYW55IGhhbmRsZXIgdGhhdCB0aGUgb3JpZ2luYWwgaXRlbSBoYWRcbiAgICAgIC5maW5kKCcjY2l2aWNybS1ob21lJylcbiAgICAgIC5iZWZvcmUoJGhvbWVMaW5rKVxuICAgICAgLnJlbW92ZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1vdmVzIHRoZSBcIklubGluZSBDdXN0b20gRGF0YVwiIGZpZWxkcyB0b3dhcmRzIHRoZSB0b3Agb2YgdGhlXG4gICAqIGVkaXQgY29udGFjdCBmb3JtXG4gICAqL1xuICBmdW5jdGlvbiByZXBvc2l0aW9uSW5saW5lQ3VzdG9tRGF0YUZpZWxkc0luRWRpdENvbnRhY3RGb3JtICgpIHtcbiAgICB2YXIgJGZpZWxkcyA9ICQoJyNJbmxpbmVfQ3VzdG9tX0RhdGEnKS5kZXRhY2goKTtcblxuICAgICRmaWVsZHMuZmluZCgnLmxhYmVsJykuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICB2YXIgJGxhYmVsQ2VsbCA9ICQodGhpcyk7XG4gICAgICB2YXIgJGZpZWxkQ2VsbCA9ICRsYWJlbENlbGwubmV4dCgpO1xuICAgICAgdmFyICRuZXdUZCA9ICQoJzx0ZC8+Jyk7XG5cbiAgICAgICRuZXdUZC5hcHBlbmQoJGxhYmVsQ2VsbC5maW5kKCdsYWJlbCcpKTtcbiAgICAgICRuZXdUZC5hcHBlbmQoJCgnPGJyLz4nKSk7XG4gICAgICAkbmV3VGQuYXBwZW5kKCRmaWVsZENlbGwuaHRtbCgpKTtcblxuICAgICAgJCgnI25pY2tfbmFtZScpLnBhcmVudCgpLmFmdGVyKCRuZXdUZCk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogTW92ZXMgdGhlIFwiSW5saW5lIEN1c3RvbSBEYXRhXCIgYmxvY2sgdG93YXJkcyB0aGUgdG9wIG9mIHRoZVxuICAgKiBwZXJzb25hbCBkZXRhaWxzIHRhYlxuICAgKi9cbiAgZnVuY3Rpb24gcmVwb3NpdGlvbklubGluZUN1c3RvbURhdGFCbG9ja0luUGVyc29uYWxEZXRhaWxzVGFiICgpIHtcbiAgICAkKCcuSW5saW5lX0N1c3RvbV9EYXRhJylcbiAgICAgIC5yZW1vdmVDbGFzcygnY3JtLWNvbGxhcHNpYmxlIGNvbGxhcHNlZCcpXG4gICAgICAuYWRkQ2xhc3MoJ2NybS1zdW1tYXJ5LWJsb2NrJylcbiAgICAgIC5pbnNlcnRBZnRlcignLmNybS1zdW1tYXJ5LWNvbnRhY3RpbmZvLWJsb2NrJylcbiAgICAgIC5maW5kKCcuY29sbGFwc2libGUtdGl0bGUnKS5oaWRlKCkuZW5kKClcbiAgICAgIC5maW5kKCcuY3JtLXN1bW1hcnktYmxvY2snKS5zaG93KCk7XG4gIH1cblxuICAvKipcbiAgICogU3dhcHMgdGhlIENpdmlDUk0gbG9nbyB3aXRoIHRoZSBDaXZpSFIgbG9nb1xuICAgKiBhbmQgd3JhcHMgaXQgaW4gYSBgbWVudW1haW4taWNvbmAgZWxlbWVudFxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gJG1lbnVJdGVtIFRoZSBjb250ZXh0IHdoZXJlIHRvIGZpbmQgdGhlIGxvZ29cbiAgICogQHJldHVybiB0aGUgd3JhcHBlciBvZiB0aGUgbG9nb1xuICAgKi9cbiAgZnVuY3Rpb24gc3dhcEFuZFdyYXBBcHBMb2dvICgkbWVudUl0ZW0pIHtcbiAgICB2YXIgJGFwcExvZ28gPSAkKCcuY3JtLWxvZ28tc20nLCAkbWVudUl0ZW0pO1xuXG4gICAgcmV0dXJuICRhcHBMb2dvXG4gICAgICAuYWRkQ2xhc3MoJ2Nocl9sb2dvIGNocl9sb2dvLS1kZWZhdWx0LWNvbG9yJylcbiAgICAgIC5yZW1vdmVDbGFzcygnY3JtLWxvZ28tc20nKVxuICAgICAgLndyYXAoJzxzcGFuIGNsYXNzPVwibWVudW1haW4taWNvblwiPicpXG4gICAgICAucGFyZW50KCk7XG4gIH1cblxuICAvKipcbiAgICogQ2l2aUNSTSBieSBkZWZhdWx0IGFwcGxpZXMgb24gaG92ZXIgdGhlIC5hY3RpdmV0YXJnZXQgY2xhc3NcbiAgICogb25seSB0byBtYWluIG1lbnUgaXRlbXMgd2l0aCBhIHN1Ym1lbnVcbiAgICpcbiAgICogVGhpcyBmdW5jdGlvbnMgbWFrZXMgc3VyZSB0aGF0IGFueSBpdGVtIGdldHMgdGhlIGNsYXNzIGFwcGxpZWQsXG4gICAqIGV2ZW4gdGhvc2Ugd2l0aCBqdXN0IGEgZGlyZWN0IGxpbmtcbiAgICovXG4gIGZ1bmN0aW9uIHRvZ2dsZUFjdGl2ZUNsYXNzT25Ib3Zlck9uQW55TWFpbk1lbnVJdGVtICgpIHtcbiAgICB2YXIgY2xhc3NOYW1lID0gJ2FjdGl2ZXRhcmdldCc7XG5cbiAgICAkKCcubWVudW1haW4nKS5ub3QoJy5jcm0tU2VsZl9TZXJ2aWNlX1BvcnRhbCcpLmhvdmVyKGZ1bmN0aW9uICgpIHtcbiAgICAgICQodGhpcykuYWRkQ2xhc3MoY2xhc3NOYW1lKTtcbiAgICB9LCBmdW5jdGlvbiAoKSB7XG4gICAgICAkKHRoaXMpLnJlbW92ZUNsYXNzKGNsYXNzTmFtZSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIHRoZSBhcnJvdyBmb3IgbWVudSBpdGVtcyB3aXRoIHN1Yi1pdGVtcywgYW5kIHJlcGxhY2VzIGl0XG4gICAqIHdpdGggYSBmb250IGF3ZXNvbWUgY2FyZXRcbiAgICovXG4gIGZ1bmN0aW9uIHVzZUZvbnRBd2Vzb21lQXJyb3dzSW5TdWJNZW51SXRlbXMgKCkge1xuICAgICQoJyNyb290LW1lbnUtZGl2IC5tZW51LWl0ZW0tYXJyb3cnKS5lYWNoKGZ1bmN0aW9uICgkZWxlbWVudCkge1xuICAgICAgdmFyICRhcnJvdyA9ICQodGhpcyk7XG5cbiAgICAgICRhcnJvdy5iZWZvcmUoJzxpIGNsYXNzPVwiZmEgZmEtY2FyZXQtcmlnaHQgbWVudS1pdGVtLWFycm93XCI+PC9pPicpO1xuICAgICAgJGFycm93LnJlbW92ZSgpO1xuICAgIH0pO1xuICB9XG59KENSTS4kLCBDUk0uXykpO1xuIiwiKGZ1bmN0aW9uICgkKSB7XG4gICd1c2Ugc3RyaWN0JztcbiAgdmFyIE11dGF0aW9uT2JzZXJ2ZXIgPSB3aW5kb3cuTXV0YXRpb25PYnNlcnZlciB8fCB3aW5kb3cuV2ViS2l0TXV0YXRpb25PYnNlcnZlciB8fCB3aW5kb3cuTW96TXV0YXRpb25PYnNlcnZlcjtcblxuICAvKlxuICBUaGlzIHBsdWdpbiBjcmVhdGVzIE11dGF0aW9uT2JzZXJ2ZXIgd2hpY2ggbGlzdGVucyB0byBhbGwgY2hhbmdlcyB0byBET00gTm9kZS5cbiAgSWYgY2hhbmdlIGhhcyBiZWVuIGRvbmUgdG8gaXQncyBhdHRyaWJ1dGVzIGNhbGxiYWNrIHdpbGwgYmUgY2FsbGVkLlxuXG4gIEBwYXJhbSB7ZnVuY3Rpb259IGNhbGxiYWNrIC0gdG8gYmUgY2FsbGVkIHdoZW4gYXR0cmlidXRlcyBjaGFuZ2VcbiAgQHJldHVybnMge0FycmF5fSAtIGxpc3Qgb2YgYWxsIG9ic2VydmVkIGVsZW1lbnRzXG4gICovXG4gICQuZm4uYXR0cmNoYW5nZSA9IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICAgIGlmIChNdXRhdGlvbk9ic2VydmVyKSB7XG4gICAgICB2YXIgb3B0aW9ucyA9IHtcbiAgICAgICAgc3VidHJlZTogZmFsc2UsXG4gICAgICAgIGF0dHJpYnV0ZXM6IHRydWVcbiAgICAgIH07XG5cbiAgICAgIHZhciBvYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKGZ1bmN0aW9uIChtdXRhdGlvbnMpIHtcbiAgICAgICAgbXV0YXRpb25zLmZvckVhY2goZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICBjYWxsYmFjay5jYWxsKGUudGFyZ2V0LCBlKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgIG9ic2VydmVyLm9ic2VydmUodGhpcywgb3B0aW9ucyk7XG4gICAgICB9KTtcbiAgICB9XG4gIH1cbn0pKENSTS4kKTtcbiIsIi8qIGdsb2JhbHMgQ1JNICovXG5cbi8qKlxuICogSGVscHMgdG8gZGlzcGxheSBwb3B1cCBtZW51cyBpbnNpZGUgI2Jvb3RzdHJhcC10aGVtZSBlbGVtZW50cywgc2luY2UgLnBhbmVsJ3NcbiAqIGFuZCBvdGhlciBCb290c3RyYXAgZWxlbWVudHMgY2xhc2ggd2l0aCBDaXZpQ1JNIHN0eWxlcyBwcm9kdWNpbmcgdW5kZXNpcmVkXG4gKiByZXN1bHRzLlxuICpcbiAqIEl0IGFsc28gaGVscHMgd2l0aCBldmVudCBiaW5kaW5ncywgaW4gY2FzZSB0aGUgb3JpZ2luYWwgcG9wdXAgYnV0dG9uIHdhc1xuICogcmVtb3ZlZCBhbmQgcmVjcmVhdGVkLCBieSBmb3J3YXJkaW5nIHRoZSBldmVudHMgdG8gdGhlIG9yaWdpbmFsIHNvdXJjZS5cbiAqL1xuKGZ1bmN0aW9uICgkKSB7XG4gICd1c2Ugc3RyaWN0JztcbiAgdmFyICRib2R5ID0gJCgnYm9keScpO1xuXG4gICRib2R5Lm9uKCdjbGljaycsICcjYm9vdHN0cmFwLXRoZW1lIC5idG4tc2xpZGUnLCBmdW5jdGlvbiAoKSB7XG4gICAgdmFyICRwb3B1cENsb25lO1xuICAgIHZhciAkYnV0dG9uID0gJCh0aGlzKTtcbiAgICB2YXIgJHBvcHVwID0gJGJ1dHRvbi5jaGlsZHJlbigndWwucGFuZWwnKTtcblxuICAgIChmdW5jdGlvbiBpbml0ICgpIHtcbiAgICAgIGNsb3NlUG9wdXBQYW5lbHMoKTtcbiAgICAgIGNyZWF0ZVBvcHVwQ2xvbmUoKTtcbiAgICAgIG9wZW5Qb3B1cENsb25lKCk7XG4gICAgICBtYXBDbG9uZUNsaWNrRXZlbnRzVG9PcmlnaW4oKTtcbiAgICAgIGxpc3RlblRvTW91c2VPdXRFdmVudCgpO1xuICAgIH0pKCk7XG5cbiAgICAvKipcbiAgICAgKiBDbG9zZXMgdGhlIGFueSBwb3B1cCBwYW5lbCB0aGF0IGlzIGN1cnJlbnRseSBvcGVuIGFuZCByZW1vdmVzIHRoZVxuICAgICAqIGAuY2l2aWhyLXBvcHVwLW9wZW5gIGNsYXNzIGZyb20gdGhlIGJvZHkuXG4gICAgICovXG4gICAgZnVuY3Rpb24gY2xvc2VQb3B1cFBhbmVscyAoKSB7XG4gICAgICAkKCcuY2l2aWhyLXBvcHVwJykucmVtb3ZlKCk7XG4gICAgICAkYm9keS5yZW1vdmVDbGFzcygnY2l2aWhyLXBvcHVwLW9wZW4nKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgY2xvbmUgb2YgdGhlIHBvcHVwIGVsZW1lbnQgYW5kIGFwcGVuZHMgaXQgdG8gdGhlIGRvY3VtZW50IGJvZHkuXG4gICAgICogVGhpcyBwcmV2ZW50cyB0aGUgcG9wdXAgdG8gYmUgaGlkZGVuIGJ5IGFueSBgb3ZlcmZsb3c6IGhpZGRlbjtgIHJ1bGUuXG4gICAgICovXG4gICAgZnVuY3Rpb24gY3JlYXRlUG9wdXBDbG9uZSAoKSB7XG4gICAgICAkcG9wdXBDbG9uZSA9ICRwb3B1cC5jbG9uZSh0cnVlKVxuICAgICAgICAuYXBwZW5kVG8oJGJvZHkpXG4gICAgICAgIC5hZGRDbGFzcygnY2l2aWhyLXBvcHVwJyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTGlzdGVucyB0byBtb3VzZSBldmVudHMgaGFwcGVuaW5nIG91dHNpZGUgdGhlIG9mIHRoZSBwYW5lbCBpbiBvcmRlciB0b1xuICAgICAqIGNsb3NlIGl0LiBUaGUgd2F5IHRvIGRldGVjdGVkIG1vdXNlIG91dCBpcyBieSBsaXN0ZW5pbmcgdG8gdGhlXG4gICAgICogLmJ0bi1zbGlkZS1hY3RpdmUgY2xhc3MgY2hhbmdlLCB3aGljaCBpcyBhZGRlZCBhbmQgcmVtb3ZlZCBieSBDaXZpQ1JNLlxuICAgICAqIHRoZSBkYXRhICphdHRyY2hhbmdlLWlzLW9uKiBpcyBzZXQgdG8gdHJ1ZSBpbiBvcmRlciB0byBhdm9pZCBhZGRpbmdcbiAgICAgKiBtdWx0aXBsZSBsaXN0ZW5lcnMgdG8gdGhlIHNhbWUgZWxlbWVudC5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBsaXN0ZW5Ub01vdXNlT3V0RXZlbnQgKCkge1xuICAgICAgLy8gSWYgQXR0ckNoYW5nZSBldmVudCBpcyBhbHJlYWR5IGxpc3RlbmVkLCB0aGVuIHNraXA6XG4gICAgICBpZiAoJGJ1dHRvbi5kYXRhKCdhdHRyY2hhbmdlLWlzLW9uJykpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICAkYnV0dG9uLmRhdGEoJ2F0dHJjaGFuZ2UtaXMtb24nLCB0cnVlKTtcbiAgICAgICRidXR0b24uYXR0cmNoYW5nZShmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIElmIGJ1dHRvbiBpcyBhbHJlYWR5IG9wZW4sIHRoZW4gc2tpcDpcbiAgICAgICAgaWYgKCRidXR0b24uaGFzQ2xhc3MoJ2J0bi1zbGlkZS1hY3RpdmUnKSkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNsb3NlUG9wdXBQYW5lbHMoKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE1hcHMgY2xpY2sgZXZlbnRzIG9uIHRoZSBwb3B1cCBvcHRpb25zIGJhY2sgdG8gdGhlaXIgb3JpZ2luYWwgc291cmNlLlxuICAgICAqIFRoaXMgaXMgZG9uZSBiZWNhdXNlIHBvcHVwIGFjdGlvbnMgYXJlIGV4ZWN1dGVkIGFzIGRlbGVnYXRlZCBldmVudHMgYW5kXG4gICAgICogdGhlIGxpc3RlbmVyIGlzIG5vdCB0aGUgKmJvZHkqIGVsZW1lbnQuXG4gICAgICovXG4gICAgZnVuY3Rpb24gbWFwQ2xvbmVDbGlja0V2ZW50c1RvT3JpZ2luICgpIHtcbiAgICAgICRwb3B1cENsb25lLmZpbmQoJ2EnKS5jbGljayhmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBhY3Rpb25JbmRleCA9ICQodGhpcykucGFyZW50KCkuaW5kZXgoKTtcblxuICAgICAgICAkcG9wdXAuZmluZCgnbGk6bnRoKCcgKyBhY3Rpb25JbmRleCArICcpIGEnKS5jbGljaygpO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogT3BlbnMgdGhlIHBvcHVwIHBhbmVsIGNsb25lXG4gICAgICogYW5kIGFkZHMgdGhlIC5jaXZpaHItcG9wdXAtb3BlbiBjbGFzcyB0byB0aGUgYm9keVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIG9wZW5Qb3B1cENsb25lICgpIHtcbiAgICAgIHZhciBidXR0b25PZmZzZXQgPSAkYnV0dG9uLm9mZnNldCgpO1xuXG4gICAgICAkcG9wdXBDbG9uZS5jc3Moe1xuICAgICAgICBsZWZ0OiArYnV0dG9uT2Zmc2V0LmxlZnQgLSAoJHBvcHVwQ2xvbmUud2lkdGgoKSAtICRidXR0b24ub3V0ZXJXaWR0aCgpKSxcbiAgICAgICAgdG9wOiArYnV0dG9uT2Zmc2V0LnRvcCArICRidXR0b24ub3V0ZXJIZWlnaHQoKVxuICAgICAgfSk7XG4gICAgICAkcG9wdXBDbG9uZS5zaG93KCk7XG4gICAgICAkYm9keS5hZGRDbGFzcygnY2l2aWhyLXBvcHVwLW9wZW4nKTtcbiAgICB9XG4gIH0pO1xufSkoQ1JNLiQpO1xuIl19 diff --git a/hrui/js/src/hrui.js b/hrui/js/src/hrui.js index a8085de481e..2bd80d64aae 100755 --- a/hrui/js/src/hrui.js +++ b/hrui/js/src/hrui.js @@ -186,13 +186,11 @@ * Manipulates, at the DOM level, the blocks/fields belonging to the * Inline Custom Data custom fields set */ - if ($('.Inline_Custom_Data').length) { - repositionPersonalDetailsBlock('.Inline_Custom_Data'); - } - - repositionPersonalDetailsBlock('.Extended_Demographics'); - function manipulateDOMOfInlineCustomData () { + if ($('.Inline_Custom_Data').length) { + repositionInlineCustomDataBlockInPersonalDetailsTab(); + } + if ($('#customFields').length < 1) { repositionInlineCustomDataFieldsInEditContactForm(); } @@ -273,15 +271,14 @@ } /** - * Moves the specified selector element to the personal details tab - * - * @param selector + * Moves the "Inline Custom Data" block towards the top of the + * personal details tab */ - function repositionPersonalDetailsBlock (selector) { - $(selector) + function repositionInlineCustomDataBlockInPersonalDetailsTab () { + $('.Inline_Custom_Data') .removeClass('crm-collapsible collapsed') .addClass('crm-summary-block') - .appendTo('.contactTopBar .contactCardLeft') + .insertAfter('.crm-summary-contactinfo-block') .find('.collapsible-title').hide().end() .find('.crm-summary-block').show(); } diff --git a/hrvisa/tests/phpunit/CRM/HRVisa/ActivityTest.php b/hrvisa/tests/phpunit/CRM/HRVisa/ActivityTest.php index 49e40ddaa7a..d822db9ec16 100644 --- a/hrvisa/tests/phpunit/CRM/HRVisa/ActivityTest.php +++ b/hrvisa/tests/phpunit/CRM/HRVisa/ActivityTest.php @@ -16,6 +16,8 @@ class CRM_HRVisa_ActivityTest extends PHPUnit_Framework_TestCase implements Head public function setUpHeadless() { return \Civi\Test::headless() ->installMe(__DIR__) + // hrdemog is necessary because it creates the Immigration fields used by the tests + ->install('org.civicrm.hrdemog') ->install('uk.co.compucorp.civicrm.hrcore') ->apply(); } diff --git a/uk.co.compucorp.civicrm.hrcontactactionsmenu/CRM/HRContactActionsMenu/Page/UserMailNotifier.php b/uk.co.compucorp.civicrm.hrcontactactionsmenu/CRM/HRContactActionsMenu/Page/UserMailNotifier.php index f3907946bd1..aadc269032f 100644 --- a/uk.co.compucorp.civicrm.hrcontactactionsmenu/CRM/HRContactActionsMenu/Page/UserMailNotifier.php +++ b/uk.co.compucorp.civicrm.hrcontactactionsmenu/CRM/HRContactActionsMenu/Page/UserMailNotifier.php @@ -14,7 +14,7 @@ class CRM_HRContactActionsMenu_Page_UserMailNotifier { public static function sendPasswordResetEmail() { $contactID = CRM_Utils_Array::value('cid', $_GET); $contactInfo = ContactHelper::getUserInformation($contactID); - $cmsUserMailNotifier = Civi::container()->get('civihr.cms.notifier'); + $cmsUserMailNotifier = Civi::container()->get('hrcore.cms_notifier'); $cmsUserMailNotifier->sendPasswordResetEmail($contactInfo); CRM_Core_Session::setStatus(ts('Password Reset Email sent'), 'Success', 'success'); @@ -30,7 +30,7 @@ public static function sendPasswordResetEmail() { public static function sendWelcomeEmail() { $contactID = CRM_Utils_Array::value('cid', $_GET); $contactInfo = ContactHelper::getUserInformation($contactID); - $cmsUserMailNotifier = Civi::container()->get('civihr.cms.notifier'); + $cmsUserMailNotifier = Civi::container()->get('hrcore.cms_notifier'); $cmsUserMailNotifier->sendWelcomeEmail($contactInfo); CRM_Core_Session::setStatus(ts('Welcome Email sent'), 'Success', 'success'); diff --git a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Form/AbstractDrupalInteractionTaskForm.php b/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Form/AbstractDrupalInteractionTaskForm.php index d328fcbf322..0997556e4af 100644 --- a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Form/AbstractDrupalInteractionTaskForm.php +++ b/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Form/AbstractDrupalInteractionTaskForm.php @@ -26,7 +26,7 @@ public function __construct( $method = 'post', $name = NULL ) { - $this->drupalUserService = Civi::container()->get('civihr.cms.drupal_user_service'); + $this->drupalUserService = Civi::container()->get('drupal_user_service'); parent::__construct($state, $action, $method, $name); } diff --git a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Hook/Disable/CustomGroupDisabler.php b/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Hook/Disable/CustomGroupDisabler.php deleted file mode 100644 index bc2369c0dc8..00000000000 --- a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Hook/Disable/CustomGroupDisabler.php +++ /dev/null @@ -1,17 +0,0 @@ -get('civihr.custom_group_status_switcher'); - - foreach ($customGroups as $groupName) { - $switcher->disable($groupName); - } - } - -} diff --git a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Hook/Enable/CustomGroupEnabler.php b/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Hook/Enable/CustomGroupEnabler.php deleted file mode 100644 index b6043723f4a..00000000000 --- a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Hook/Enable/CustomGroupEnabler.php +++ /dev/null @@ -1,21 +0,0 @@ -enable($groupName); - } - } - -} diff --git a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Hook/Uninstall/CustomGroupRemover.php b/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Hook/Uninstall/CustomGroupRemover.php deleted file mode 100644 index 302e5ee0664..00000000000 --- a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Hook/Uninstall/CustomGroupRemover.php +++ /dev/null @@ -1,25 +0,0 @@ - 'id', 'name' => $customGroupName]; - $result = civicrm_api3('CustomGroup', 'get', $params); - - if ($result['count'] != 1) { - continue; - } - $customGroup = array_shift($result['values']); - - civicrm_api3('CustomGroup', 'delete', ['id' => $customGroup['id']]); - } - } -} diff --git a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Service/CustomGroupStatusSwitcher.php b/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Service/CustomGroupStatusSwitcher.php deleted file mode 100644 index f381b3be7d5..00000000000 --- a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Service/CustomGroupStatusSwitcher.php +++ /dev/null @@ -1,102 +0,0 @@ -changeStatus($customGroupName, TRUE); - } - - /** - * Disable a custom group and all its fields - * - * @param string $customGroupName - */ - public function disable($customGroupName) { - $this->changeStatus($customGroupName, FALSE); - } - - /** - * Switches the status for custom group and all its fields - * - * @param string $customGroupName - * @param bool $status - */ - private function changeStatus($customGroupName, $status) { - $customGroup = $this->getCustomGroup($customGroupName); - - if (!$customGroup) { - $err = sprintf('Could not find group with name "%s"', $customGroupName); - throw new \Exception($err); - } - - $customGroupId = (int) $customGroup['id']; - $this->changeGroupStatus($customGroupId, $status); - $this->changeAllGroupFieldsStatus($customGroupId, $status); - } - - /** - * Update the 'is_active' status for a custom group - * - * @param int $customGroupId - * @param bool $status - */ - private function changeGroupStatus($customGroupId, $status) { - $params = ['id' => $customGroupId, 'is_active' => $status]; - civicrm_api3('CustomGroup', 'create', $params); - } - - /** - * Update the 'is_active' status for all custom fields for a group - * - * @param int $customGroupId - * @param bool $status - */ - private function changeAllGroupFieldsStatus($customGroupId, $status) { - $fields = $this->getAllCustomFields($customGroupId); - - foreach ($fields as $field) { - $params = ['id' => $field['id'], 'is_active' => $status]; - // Custom field endpoint freaks out if custom_group_id is missing - $params['custom_group_id'] = $field['custom_group_id']; - civicrm_api3('CustomField', 'create', $params); - } - } - - /** - * Fetches all custom fields for a custom group - * - * @param int $customGroupId - * - * @return array - */ - private function getAllCustomFields($customGroupId) { - $params = ['custom_group_id' => $customGroupId]; - $result = civicrm_api3('CustomField', 'get', $params); - - return $result['values']; - } - - /** - * Gets a custom group based on name, returns null if group doesn't exist - * - * @param string $customGroupName - * - * @return mixed|null - */ - private function getCustomGroup($customGroupName) { - $params = ['name' => $customGroupName]; - $result = civicrm_api3('CustomGroup', 'get', $params); - - if ($result['count'] != 1) { - return NULL; - } - - return array_shift($result['values']); - } - -} diff --git a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Test/Fabricator/CustomField.php b/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Test/Fabricator/CustomField.php deleted file mode 100644 index e2030ae18c1..00000000000 --- a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Test/Fabricator/CustomField.php +++ /dev/null @@ -1,23 +0,0 @@ - 'test_custom_field', - 'html_type' => 'Text', - 'data_type' => 'String', - ]; - - public static function fabricate($params = []) { - $params = array_merge(self::$defaultParams, $params); - - if (!isset($params['label'])) { - $params['label'] = $params['name']; - } - - $result = civicrm_api3('CustomField', 'create', $params); - - return array_shift($result['values']); - } - -} diff --git a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Test/Fabricator/CustomGroup.php b/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Test/Fabricator/CustomGroup.php deleted file mode 100644 index 5ac6eecbbdd..00000000000 --- a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Test/Fabricator/CustomGroup.php +++ /dev/null @@ -1,28 +0,0 @@ - 'test_custom_group_' . $count, - 'title' => 'Test Custom Group ' . $count, - 'extends' => 'Individual' - ]; - } - -} diff --git a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Upgrader.php b/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Upgrader.php index 208c2f772d5..2d69d9e62dc 100755 --- a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Upgrader.php +++ b/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Upgrader.php @@ -25,7 +25,6 @@ class CRM_HRCore_Upgrader extends CRM_HRCore_Upgrader_Base { use CRM_HRCore_Upgrader_Steps_1015; use CRM_HRCore_Upgrader_Steps_1016; use CRM_HRCore_Upgrader_Steps_1017; - use CRM_HRCore_Upgrader_Steps_1021; use CRM_HRCore_Upgrader_Steps_1018; use CRM_HRCore_Upgrader_Steps_1019; use CRM_HRCore_Upgrader_Steps_1020; @@ -59,18 +58,10 @@ class CRM_HRCore_Upgrader extends CRM_HRCore_Upgrader_Base { 'Validate Email Address from Mailings.' ]; - /** - * A list of directories to be scanned for XML installation files - * - * @var array - */ - private $xmlDirectories = ['CustomGroups']; - /** * Callback called when the extension is installed */ public function install() { - $this->processXMLInstallationFiles(); $this->setScheduledJobsDefaultStatus(); $this->deleteLocationTypes(); $this->createRequiredLocationTypes(); @@ -79,25 +70,6 @@ public function install() { $this->runAllUpgraders(); } - /** - * Scans all the directories in $xmlDirectories for installation files - * (xml files ending with _install.xml) and processes them. - */ - private function processXMLInstallationFiles() { - foreach($this->xmlDirectories as $directory) { - $files = glob($this->extensionDir . "/xml/{$directory}/*_install.xml"); - if (is_array($files)) { - foreach ($files as $file) { - $this->executeCustomDataFileByAbsPath($file); - } - } - } - // Flush the cache so that all pseudoconstants can be re-read from db - // This is to avoid issues when running upgraders during installation - // whereby some pseudoconstants were not available. - CRM_Core_PseudoConstant::flush(); - } - /** * Callback method called when the extension is uninstalled. * diff --git a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Upgrader/Steps/1021.php b/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Upgrader/Steps/1021.php deleted file mode 100644 index 0a59b627d43..00000000000 --- a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Upgrader/Steps/1021.php +++ /dev/null @@ -1,27 +0,0 @@ - $key]); - civicrm_api3('Extension', 'uninstall', ['keys' => $key]); - - return TRUE; - } - -} diff --git a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Upgrader/Steps/1025.php b/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Upgrader/Steps/1025.php deleted file mode 100644 index 56cf2743be4..00000000000 --- a/uk.co.compucorp.civicrm.hrcore/CRM/HRCore/Upgrader/Steps/1025.php +++ /dev/null @@ -1,54 +0,0 @@ -up1025_deleteExtendDemographicFields([ - 'Ethnicity', - 'Religion', - 'Sexual_Orientation', - ]); - - return TRUE; - } - - /** - * Deletes Custom Demographic Fields only if they are not used - * - * @param array $fieldsToDelete - */ - private function up1025_deleteExtendDemographicFields($fieldsToDelete) { - $customGroup = civicrm_api3('CustomGroup', 'get', [ - 'name' => 'Extended_Demographics', - ]); - $customGroup = array_shift($customGroup['values']); - $customFields = civicrm_api3('CustomField', 'get', [ - 'name' => ['IN' => $fieldsToDelete], - ]); - $tableName = $customGroup['table_name']; - foreach ($customFields['values'] as $customField) { - $column = $customField['column_name']; - $queryFormat = 'SELECT COUNT(id) FROM %s' - . ' WHERE %s NOT LIKE "%%Not Applicable%%"' - . ' AND %s IS NOT NULL' - . ' AND %s <> ""'; - - $query = sprintf($queryFormat, $tableName, $column, $column, $column); - $customFieldItems = CRM_Core_DAO::singleValueQuery($query); - if ($customFieldItems > 0) { - continue; - } - - civicrm_api3('CustomField', 'delete', [ - 'id' => $customField['id'], - ]); - } - } - -} diff --git a/uk.co.compucorp.civicrm.hrcore/api/v3/Job/CheckCivihrVersion.php b/uk.co.compucorp.civicrm.hrcore/api/v3/Job/CheckCivihrVersion.php index 22f3b99120a..d1956223a66 100644 --- a/uk.co.compucorp.civicrm.hrcore/api/v3/Job/CheckCivihrVersion.php +++ b/uk.co.compucorp.civicrm.hrcore/api/v3/Job/CheckCivihrVersion.php @@ -7,8 +7,8 @@ */ function civicrm_api3_job_check_civihr_version() { $container = Civi::container(); - $currentStats = $container->get('civihr.stats_cache')->fetchCurrent(); - $container->get('civihr.stats_sender')->send($currentStats); + $currentStats = $container->get('civihr_stats_cache')->fetchCurrent(); + $container->get('civihr_stats_sender')->send($currentStats); return civicrm_api3_create_success(); } diff --git a/uk.co.compucorp.civicrm.hrcore/config/container/container.xml b/uk.co.compucorp.civicrm.hrcore/config/container/container.xml index 3055b64c30b..ffa8e04b42c 100644 --- a/uk.co.compucorp.civicrm.hrcore/config/container/container.xml +++ b/uk.co.compucorp.civicrm.hrcore/config/container/container.xml @@ -3,50 +3,48 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - 10 + 10 - - - - + + + - - - + + + - %civihr.connection_timeout% + %connection_timeout% - + - - + + - diff --git a/uk.co.compucorp.civicrm.hrcore/hrcore.php b/uk.co.compucorp.civicrm.hrcore/hrcore.php index afc7549338b..6c3eb765a2e 100644 --- a/uk.co.compucorp.civicrm.hrcore/hrcore.php +++ b/uk.co.compucorp.civicrm.hrcore/hrcore.php @@ -180,14 +180,6 @@ function hrcore_civicrm_postInstall() { * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_uninstall */ function hrcore_civicrm_uninstall() { - $listeners = [ - new CRM_HRCore_Hook_Uninstall_CustomGroupRemover() - ]; - - foreach ($listeners as $listener) { - $listener->handle(); - } - _hrcore_civix_civicrm_uninstall(); } @@ -197,19 +189,6 @@ function hrcore_civicrm_uninstall() { * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_enable */ function hrcore_civicrm_enable() { - // _hrcore_civix_civicrm_config() will add this extension to the include path. - // We need to do this here because before extension is enabled the config - // hook is not called for it - _hrcore_civix_civicrm_config(); - - $listeners = [ - new CRM_HRCore_Hook_Enable_CustomGroupEnabler() - ]; - - foreach ($listeners as $listener) { - $listener->handle(); - } - _hrcore_civix_civicrm_enable(); } @@ -219,14 +198,6 @@ function hrcore_civicrm_enable() { * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_disable */ function hrcore_civicrm_disable() { - $listeners = [ - new CRM_HRCore_Hook_Disable_CustomGroupDisabler() - ]; - - foreach ($listeners as $listener) { - $listener->handle(); - } - _hrcore_civix_civicrm_disable(); } diff --git a/uk.co.compucorp.civicrm.hrcore/tests/phpunit/CRM/HRCore/Helper/ExtensionHelperTest.php b/uk.co.compucorp.civicrm.hrcore/tests/phpunit/CRM/HRCore/Helper/ExtensionHelperTest.php index e67d3ea052d..f7bde0da97f 100644 --- a/uk.co.compucorp.civicrm.hrcore/tests/phpunit/CRM/HRCore/Helper/ExtensionHelperTest.php +++ b/uk.co.compucorp.civicrm.hrcore/tests/phpunit/CRM/HRCore/Helper/ExtensionHelperTest.php @@ -10,15 +10,16 @@ class CRM_HRCore_Helper_ExtensionHelperTest extends CRM_HRCore_Test_BaseHeadless /** * @var string */ - private $extensionKey = 'uk.co.compucorp.civicrm.hremails'; + private $hrCoreKey = 'uk.co.compucorp.civicrm.hrcore'; public function testCheckIsFalseAfterExtensionIsDisabled() { - civicrm_api3('Extension', 'disable', ['keys' => $this->extensionKey]); - $this->assertFalse(ExtensionHelper::isExtensionEnabled($this->extensionKey)); + // hrcore is enabled by default in CRM_HRCore_Test_BaseHeadlessTest + civicrm_api3('Extension', 'disable', ['keys' => $this->hrCoreKey]); + $this->assertFalse(ExtensionHelper::isExtensionEnabled($this->hrCoreKey)); } public function testCheckIsTrueAfterExtensionIsEnabled() { - civicrm_api3('Extension', 'enable', ['keys' => $this->extensionKey]); - $this->assertTrue(ExtensionHelper::isExtensionEnabled($this->extensionKey)); + civicrm_api3('Extension', 'enable', ['keys' => $this->hrCoreKey]); + $this->assertTrue(ExtensionHelper::isExtensionEnabled($this->hrCoreKey)); } } diff --git a/uk.co.compucorp.civicrm.hrcore/tests/phpunit/CRM/HRCore/Service/CustomGroupStatusSwitcherTest.php b/uk.co.compucorp.civicrm.hrcore/tests/phpunit/CRM/HRCore/Service/CustomGroupStatusSwitcherTest.php deleted file mode 100644 index a1d65aacdd3..00000000000 --- a/uk.co.compucorp.civicrm.hrcore/tests/phpunit/CRM/HRCore/Service/CustomGroupStatusSwitcherTest.php +++ /dev/null @@ -1,140 +0,0 @@ -disable(self::$customGroup['name']); - - // check that all custom fields were disabled - foreach (self::$customFields as $customField) { - $id = $customField['id']; - $updatedField = civicrm_api3('CustomField', 'getsingle', ['id' => $id]); - $this->assertEquals(0, $updatedField['is_active']); - } - - // check custom group was disabled - $updatedGroup = civicrm_api3('CustomGroup', 'getsingle', ['id' => $groupId]); - $this->assertEquals(0, $updatedGroup['is_active']); - - } - - public function testEnablingWillEnableAllFields() { - $groupId = self::$customGroup['id']; - // disable the group - civicrm_api3('CustomGroup', 'create', ['id' => $groupId, 'is_active' => 0]); - - // disable the fields - foreach (self::$customFields as $customField) { - civicrm_api3('CustomField', 'create', [ - 'id' => $customField['id'], - 'is_active' => 0, - ]); - } - - $switcher = new CustomGroupStatusSwitcher(); - $switcher->enable(self::$customGroup['name']); - - // check that all custom fields were enabled - foreach (self::$customFields as $customField) { - $id = $customField['id']; - $updatedField = civicrm_api3('CustomField', 'getsingle', ['id' => $id]); - $this->assertEquals(1, $updatedField['is_active']); - } - - // check custom group was enabled - $updatedGroup = civicrm_api3('CustomGroup', 'getsingle', ['id' => $groupId]); - $this->assertEquals(1, $updatedGroup['is_active']); - } - - public function testNonExistingGroupNameWillThrowException() { - $groupName = 'Lala'; - $expectedMessage = 'Could not find group with name "Lala"'; - $this->setExpectedException(\Exception::class, $expectedMessage); - $switcher = new CustomGroupStatusSwitcher(); - $switcher->enable($groupName); - } - - /** - * CiviCRM test transactions are broken by custom group creation. If you - * create and subsequently delete a custom group in a test it will drop the - * table but leave the civicrm_custom_group entry. This means the next - * time the test is run it will fail when it tries to drop a table that - * doesn't exist. - * - * Similarly with custom fields, if you drop one inside a test the column - * will be dropped outside of the transaction, but the field will only be - * dropped inside the transaction, meaning the next time you try to delete - * a custom group it will fail because it tries to drop columns that don't - * exist. - * - * To avoid these problems all custom group / field creation and deletion is - * done outside the test. The CiviTestListener manages transactions in - * SetUp and TearDown, so we use the "BeforeClass" and "AfterClass" methods - */ - public static function setUpBeforeClass() { - // If the last test critically errored the group might still exist - self::deleteCustomGroupIfExists('Foo'); - - self::$customGroup = CustomGroupFabricator::fabricate(['name' => 'Foo']); - self::createCustomFields(2); - } - - /** - * Clean up everything created in this test class - */ - public static function tearDownAfterClass() { - static::deleteCustomGroupIfExists(self::$customGroup['name']); - } - - /** - * Checks if a custom group exists (by name) and deletes it if it does - * - * @param string $groupName - */ - private static function deleteCustomGroupIfExists($groupName) { - $existing = civicrm_api3('CustomGroup', 'get', ['name' => $groupName]); - if ($existing['count'] > 0) { - $existing = array_shift($existing['values']); - civicrm_api3('CustomGroup', 'delete', ['id' => $existing['id']]); - } - } - - /** - * Create some custom fields for the test custom group - * - * @param int $count - */ - private static function createCustomFields($count) { - $customFields = []; - - for ($i = 0; $i < $count; $i++) { - $params['custom_group_id'] = self::$customGroup['id']; - $params['name'] = 'bar_' . $i; - $customFields[] = CustomFieldFabricator::fabricate($params); - } - - self::$customFields = $customFields; - } - -} diff --git a/uk.co.compucorp.civicrm.hrsampledata/resources/csv/civicrm_option_value.csv b/uk.co.compucorp.civicrm.hrsampledata/resources/csv/civicrm_option_value.csv index ed6ff7da462..70beb41a1e1 100644 --- a/uk.co.compucorp.civicrm.hrsampledata/resources/csv/civicrm_option_value.csv +++ b/uk.co.compucorp.civicrm.hrsampledata/resources/csv/civicrm_option_value.csv @@ -85,6 +85,9 @@ name,phone_type,Mobile,Mobile,,0,0,0,0,,0 name,marital_status_20130913084916,Single,Single,,0,0,0,0,,0 name,marital_status_20130913084916,Married,Married,,0,0,0,0,,0 name,marital_status_20130913084916,Divorced,Divorced,,0,0,0,0,,0 +name,sexual_orientation_20130725124348,Not Applicable,Not Applicable,,0,0,0,0,,0 +name,religion_20130725124132,Not Applicable,Not Applicable,,0,0,0,0,,0 +name,ethnicity_20130725123943,Not Applicable,Not Applicable,,0,0,0,0,,0 name,hrjc_benefit_type,Fixed,Fixed,,0,0,0,0,,0 name,hrjc_benefit_name,Bike,Bike,,0,0,0,0,,0 name,postal_greeting,Dear {contact.first_name},Dear {contact.first_name},,1,1,0,0,,0 diff --git a/uk.co.compucorp.civicrm.hrsampledata/tests/phpunit/CRM/HRSampleData/BaseCSVProcessorTest.php b/uk.co.compucorp.civicrm.hrsampledata/tests/phpunit/CRM/HRSampleData/BaseCSVProcessorTest.php index 04c4a161ff7..59bd263f19d 100644 --- a/uk.co.compucorp.civicrm.hrsampledata/tests/phpunit/CRM/HRSampleData/BaseCSVProcessorTest.php +++ b/uk.co.compucorp.civicrm.hrsampledata/tests/phpunit/CRM/HRSampleData/BaseCSVProcessorTest.php @@ -20,6 +20,7 @@ public function setUpHeadless() { ->install('com.civicrm.hrjobroles') ->install('org.civicrm.hrrecruitment') ->install('org.civicrm.hremergency') + ->install('org.civicrm.hrdemog') ->install('org.civicrm.hrbank') ->install('uk.co.compucorp.civicrm.tasksassignments') ->install('org.civicrm.hrcase') diff --git a/uk.co.compucorp.civicrm.hrsampledata/tests/phpunit/CRM/HRSampleData/Importer/ExtendedDemographicsTest.php b/uk.co.compucorp.civicrm.hrsampledata/tests/phpunit/CRM/HRSampleData/Importer/ExtendedDemographicsTest.php index a429706bc4b..60a7184a6eb 100644 --- a/uk.co.compucorp.civicrm.hrsampledata/tests/phpunit/CRM/HRSampleData/Importer/ExtendedDemographicsTest.php +++ b/uk.co.compucorp.civicrm.hrsampledata/tests/phpunit/CRM/HRSampleData/Importer/ExtendedDemographicsTest.php @@ -22,6 +22,9 @@ public function testProcess() { $this->rows[] = [ $this->testContact['id'], 1020, + 'Not Applicable', + 'Not Applicable', + 'Not Applicable', 'Single', ]; @@ -40,6 +43,9 @@ private function importHeadersFixture() { return [ 'entity_id', 'Nationality', + 'Ethnicity', + 'Religion', + 'Sexual_Orientation', 'Marital_Status', ]; }