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',
];
}