- <?php
-  * @file
-  * Allows users to change the color scheme of themes.
-  */
- 
-  * Implements hook_theme().
-  */
- function color_theme() {
-   return array(
-     'color_preview' => array(
-       'render element' => 'form',
-       'file' => 'color.theme.inc',
-     ),
-   );
- }
- 
-  * Implements hook_form_FORM_ID_alter().
-  */
- function color_form_system_theme_settings_alter(&$form, &$form_state) {
-   if (isset($form_state['build_info']['args'][0])
-       && ($theme_name = $form_state['build_info']['args'][0])
-       && ($theme_info = color_get_info($theme_name))
-       && isset($theme_info['fields'])) {
-     $form['color'] = array(
-       '#type' => 'fieldset',
-       '#title' => t('Color scheme'),
-       '#weight' => -1,
-       '#attributes' => array(
-         'id' => 'color_scheme_form',
-         'class' => array('color-form'),
-       ),
-     );
- 
-     $theme_info['schemes'][''] = array('title' => t('Custom'), 'colors' => array());
-     $color_sets = array();
-     $schemes = array();
-     foreach ($theme_info['schemes'] as $key => $scheme) {
-       $color_sets[$key] = $scheme['title'];
-       $schemes[$key] = $scheme['colors'];
-       $schemes[$key] += $theme_info['schemes']['default']['colors'];
-     }
- 
-     
-     
-     $current_scheme = theme_get_setting('color.palette', $theme_name);
-     foreach ($schemes as $key => $scheme) {
-       if ($current_scheme == $scheme) {
-         $scheme_name = $key;
-         break;
-       }
-     }
-     if (empty($scheme_name)) {
-       if (empty($current_scheme)) {
-         $scheme_name = 'default';
-       }
-       else {
-         $scheme_name = '';
-       }
-     }
- 
-     
-     $preview_url = url('<front>', array(
-       'query' => array(
-         'preview' => $theme_name
-       ),
-       'absolute' => TRUE,
-     ));
-     $preview_markup = theme('color_preview', array('preview_url' => $preview_url));
- 
-     $base = backdrop_get_path('module', 'color');
-     
-     $form['color']['scheme'] = array(
-       '#type' => 'select',
-       '#title' => t('Color set'),
-       '#options' => $color_sets,
-       '#default_value' => $scheme_name,
-       '#attributes' => array(
-         'data-color-schemes' => backdrop_json_encode($schemes),
-         'data-color-theme-name' => $theme_name,
-         'data-color-preview-markup' => $preview_markup,
-         'data-color-preview-token' => backdrop_get_token('color_token'),
-       ),
-       '#attached' => array(
-         
-         'css' => array(
-           $base . '/css/color.admin.css' => array(),
-         ),
-         
-         'js' => array(
-           $base . '/js/color.js'
-         ),
-       ),
-     );
- 
-     $form['color']['palette'] = array(
-       '#type' => 'container',
-       '#attributes' => array('id' => 'palette'),
-       '#tree' => TRUE,
-     );
- 
-     
-     foreach ($theme_info['fields'] as $name => $label) {
-       
-       if (!isset($form['#color_elements']) || !in_array($name, $form['#color_elements'])) {
-         $form['color']['palette'][$name] = color_get_color_element($theme_name, $name, $form);
-       }
-     }
- 
-     $form['color']['theme'] = array('#type' => 'value', '#value' => $theme_name);
-     $form['color']['info'] = array('#type' => 'value', '#value' => $theme_info);
- 
-     $form['#validate'][] = 'color_scheme_form_validate';
-     array_unshift($form['#submit'], 'color_scheme_form_submit');
- 
-     
-     
-     if ($theme_name === 'bartik') {
-       module_load_include('inc', 'color', 'color.legacy');
-       bartik_form_system_theme_settings_alter($form, $form_state);
-     }
-   }
- }
- 
-  * Creates the render array for a color element.
-  *
-  * The function also stores a list of which color elements have already been
-  * generated, so that the color module does not attempt to print out color
-  * settings twice.
-  *
-  * @param string $theme_name
-  *   The theme to get color settings from.
-  * @param string $color_name
-  *   The name of the color element to return.
-  * @param array $form
-  *   The form array for the theme settings form.
-  *
-  * @return array
-  *   The render array for the color element.
-  *
-  * @since 1.12.2
-  */
- function color_get_color_element($theme_name, $color_name, &$form) {
-   
-   $theme_info = color_get_info($theme_name);
-   $palette = color_get_palette($theme_name);
- 
-   
-   $form['#color_elements'][] = $color_name;
- 
-   
-   return array(
-     '#type' => 'color',
-     '#title' => check_plain($theme_info['fields'][$color_name]),
-     '#value_callback' => 'color_palette_color_value',
-     '#default_value' => $palette[$color_name],
-     '#size' => 8,
-     '#parents' => array('palette', $color_name),
-     '#attributes' => array(
-       'data-color-name' => $color_name,
-     ),
-   );
- }
- 
-  * Implements hook_css_alter().
-  *
-  * Replaces style sheets with color-altered style sheets.
-  */
- function color_css_alter(&$css) {
-   global $theme_key;
-   $preview_theme = _color_preview_theme();
-   if ($preview_theme) {
-     
-     $theme_info = color_get_info($preview_theme);
-     if ($theme_info) {
-       $theme_path = backdrop_get_path('theme', $preview_theme);
-       if (isset($_SESSION['color'][$theme_key])) {
-         $preview_data = $_SESSION['color'][$theme_key];
-         $paths = array(
-           'source' => $theme_path . '/',
-           'map' => array(),
-         );
-         foreach ($theme_info['css'] as $file) {
-           $filename = _color_get_file_path($file, $preview_theme);
-           $stylesheet = file_get_contents($filename);
-           $paths['source'] = backdrop_get_path('theme', _color_get_theme_from_file($file, $preview_theme));
-           $base = base_path() . dirname($filename) . '/';
-           _backdrop_build_css_path(NULL, $base);
- 
-           $stylesheet = preg_replace_callback('/url\([\'"]?(?![a-z]+:|\/+)([^\'")]+)[\'"]?\)/i', '_backdrop_build_css_path', $stylesheet);
-           $stylesheet = _color_rewrite_stylesheet($preview_theme, $theme_info, $paths, $preview_data['palette'], $stylesheet);
- 
-           foreach ($css as $path => $data) {
-             if ($path == $filename) {
-               $css[$path]['type'] = 'inline';
-               $css[$path]['preprocess'] = 'false';
-               $css[$path]['data'] = $stylesheet;
-               break;
-             }
-           }
-         }
-       }
-     }
-   }
-   if (!isset($preview_data)) {
-     
-     $color_paths = theme_get_setting('color.stylesheets');
- 
-     if (!empty($color_paths)) {
-       $info = color_get_info($theme_key);
- 
-       
-       $old_paths = array();
-       foreach ($info['css'] as $file) {
-         
-         
-         $old_paths[$file] = _color_get_file_path($file, $theme_key);
-       }
- 
-       
-       foreach($color_paths as $color_path) {
-         $basename = backdrop_basename($color_path);
-         if (array_key_exists($basename, $old_paths)) {
-           
-           
-           $css[$old_paths[$basename]]['data'] = $color_path;
-         }
-       }
-     }
-   }
- }
- 
-  * Implements hook_menu().
-  */
- function color_menu() {
-   $items = array();
- 
-   $items['color/save_preview_settings/%'] = array(
-     'page callback' => 'color_save_preview_settings',
-     'page arguments' => array(2),
-     'type' => MENU_CALLBACK,
-     'access arguments' => array('administer themes'),
-     'delivery callback' => 'backdrop_json_deliver',
-   );
- 
-   return $items;
- }
- 
-  * Callback function to handle saving preview settings to the user's session.
-  */
- function color_save_preview_settings($theme_name) {
-   if (!isset($_GET['token']) || !backdrop_valid_token($_GET['token'], "color_token")) {
-     return MENU_ACCESS_DENIED;
-   }
- 
-   $themes = list_themes();
-   if (in_array($theme_name, array_keys($themes))) {
-     $theme_info = color_get_info($theme_name);
- 
-     
-     if (isset($_POST['scheme'])
-       && !empty($_POST['scheme'])
-       && in_array($_POST['scheme'], array_keys($theme_info['schemes']))) {
-       $scheme = $_POST['scheme'];
-     }
-     else {
-       $scheme = '';
-     }
- 
-     
-     if (isset($_POST['palette']) && is_array($_POST['palette'])) {
-       $palette = $_POST['palette'];
-       foreach ($palette as $field => $color) {
-         if (!in_array($field, array_keys($theme_info['fields'])) || !color_valid_hexadecimal_string($color)) {
-           unset($palette[$field]);
-         }
-       }
-     }
- 
-     $_SESSION['color'][$theme_name] = array(
-       'scheme' => $scheme,
-       'palette' => $palette,
-     );
- 
-     $data = array('success' => 1);
-     backdrop_json_output($data);
-   }
- }
- 
-  * Implements hook_custom_theme().
-  */
- function color_custom_theme() {
-   $preview = _color_preview_theme();
-   if ($preview) {
-     
-     if (module_exists('admin_bar')) {
-       admin_bar_suppress();
-     }
-     return $preview;
-   }
- }
- 
-  * Implements hook_url_outbound_alter().
-  */
- function color_url_outbound_alter(&$path, &$options, $original_path) {
-   $preview = &backdrop_static(__FUNCTION__);
-   if (!isset($preview)) {
-     $preview = _color_preview_theme();
-   }
- 
-   if ($preview) {
-     $options['query']['preview'] = $preview;
-   }
- }
- 
-  * Implements hook_config_create().
-  */
- function color_config_create(Config $staging_config) {
-   _color_config_save($staging_config);
- }
- 
-  * Implements hook_config_update().
-  */
- function color_config_update(Config $staging_config, Config $active_config) {
-   _color_config_save($staging_config);
- }
- 
-  * Shared callback used by color_config_create() and hook_config_update().
-  *
-  * @param Config $staging_config
-  *   The configuration about to be imported into the site.
-  */
- function _color_config_save(Config $staging_config) {
-   
-   $config_name = $staging_config->getName();
-   list($theme_name, $settings) = explode('.', $config_name);
-   if ($settings === 'settings') {
-     $themes = list_themes();
-     if (array_key_exists($theme_name, $themes)) {
-       $new_color_config = $staging_config->get('color');
-       $color_info = color_get_info($theme_name);
-       if ($color_info) {
-         $palette = isset($new_color_config['palette']) ? $new_color_config['palette'] : NULL;
-         $updated_config = color_save_configuration($theme_name, $color_info, $palette);
-         
-         
-         $staging_config->set('color', $updated_config);
-       }
-     }
-   }
- }
- 
-  * Retrieves the Color module information for a particular theme.
-  */
- function color_get_info($theme) {
-   static $color_info = array();
- 
-   if (!isset($color_info[$theme])) {
-     $info = array(); 
-     $path = backdrop_get_path('theme', $theme);
-     $file = BACKDROP_ROOT . '/' . $path . '/color/color.inc';
-     if ($path && file_exists($file)) {
-       include $file;
-     }
- 
-     $themes = list_themes();
-     $theme_info = $themes[$theme];
- 
-     if (empty($info) || !isset($info['css'])) {
-       $info['css'] = array();
-       if (isset($theme_info->stylesheets)) {
-         foreach ($theme_info->stylesheets as $group) {
-           $info['css'] = array_merge($info['css'], array_keys($group));
-         }
-       }
-     }
- 
-     foreach ($info['css'] as $key => $file) {
-       $info['css'][$key] = backdrop_basename($file);
-     }
- 
-     if (isset($theme_info->base_theme) && !empty($theme_info->base_theme)) {
-       $base_info = color_get_info($theme_info->base_theme);
-       $info = backdrop_array_merge_deep($info, $base_info);
-     }
- 
-     $info['css'] = array_unique($info['css']);
- 
-     $color_info[$theme] = $info;
-   }
- 
-   return $color_info[$theme];
- }
- 
-  * Retrieves the color palette for a particular theme.
-  */
- function color_get_palette($theme, $default = FALSE) {
-   
-   $info = color_get_info($theme);
-   $palette = $info['schemes']['default']['colors'];
-   foreach ($palette as $item => $color) {
-     $palette[$item] = backdrop_strtolower($color);
-   }
-   
-   if (!$default && ($theme_palette = theme_get_setting('color.palette', $theme))) {
-     foreach ($theme_palette as $color_name => $color_code) {
-       $palette[$color_name] = $color_code;
-     }
-   }
-   return $palette;
- }
- 
-  * Determines the value for a palette color field.
-  *
-  * @param $element
-  *   The form element whose value is being populated.
-  * @param $input
-  *   The incoming input to populate the form element. If this is FALSE,
-  *   the element's default value should be returned.
-  * @param $form_state
-  *   A keyed array containing the current state of the form.
-  *
-  * @return
-  *   The data that will appear in the $form_state['values'] collection for this
-  *   element. Return nothing to use the default.
-  */
- function color_palette_color_value($element, $input = FALSE, $form_state = array()) {
-   
-   
-   
-   if ($input !== FALSE) {
-     
-     
-     $value = form_type_textfield_value($element, $input, $form_state);
-     if (!$value || !isset($form_state['complete form']['#token']) || color_valid_hexadecimal_string($value) || backdrop_valid_token($form_state['values']['form_token'], $form_state['complete form']['#token'])) {
-       return $value;
-     }
-     else {
-       return $element['#default_value'];
-     }
-   }
- }
- 
-  * Determines if a hexadecimal CSS color string is valid.
-  *
-  * @param $color
-  *   The string to check.
-  *
-  * @return
-  *   TRUE if the string is a valid hexadecimal CSS color string, or FALSE if it
-  *   isn't.
-  */
- function color_valid_hexadecimal_string($color) {
-   return preg_match('/^#([a-f0-9]{3}){1,2}$/iD', $color);
- }
- 
- 
-  * Returns the name of the theme currently being previewed.
-  *
-  * @return string
-  *   The name of the theme currently being previewed, or an empty string if the
-  *   logged in user does not have access to administer themes.
-  */
- function _color_preview_theme() {
-   if (user_access('administer themes')) {
-     if (isset($_GET['preview'])) {
-       $themes = list_themes();
-       if (in_array($_GET['preview'], array_keys($themes))) {
-         return $_GET['preview'];
-       }
-     }
-   }
-   return '';
- }
- 
-  * Form validation handler for color_scheme_form().
-  *
-  * @see color_scheme_form_submit()
-  */
- function color_scheme_form_validate($form, &$form_state) {
-   
-   foreach ($form_state['values']['palette'] as $key => $color) {
-     if (!color_valid_hexadecimal_string($color)) {
-       form_set_error('palette][' . $key, t('You must enter a valid hexadecimal color value for %name.', array('%name' => $form['color']['palette'][$key]['#title'])));
-     }
-   }
- }
- 
-  * Form submission handler for color_scheme_form().
-  *
-  * @see color_scheme_form_validate()
-  */
- function color_scheme_form_submit($form, &$form_state) {
-   
-   if (!isset($form_state['values']['info'])) {
-     return;
-   }
-   $theme = $form_state['values']['theme'];
-   $info = $form_state['values']['info'];
- 
-   
-   unset($form_state['values']['info']);
- 
-   
-   $palette = $form_state['values']['palette'];
-   if ($form_state['values']['scheme'] != '') {
-     foreach ($palette as $key => $color) {
-       if (isset($info['schemes'][$form_state['values']['scheme']]['colors'][$key])) {
-         $palette[$key] = $info['schemes'][$form_state['values']['scheme']]['colors'][$key];
-       }
-     }
-     $palette += $info['schemes']['default']['colors'];
-   }
- 
-   
-   unset($form_state['values']['scheme']);
-   unset($form_state['values']['palette']);
-   unset($_SESSION['color']);
- 
-   
-   $form_state['values']['color'] = color_save_configuration($theme, $info, $palette);
- }
- 
-  * Implements hook_flush_caches().
-  */
- function color_flush_caches() {
-   
-   color_rebuild_settings();
- }
- 
-  * Rebuild color scheme info.
-  */
- function color_rebuild_settings($theme_name = NULL) {
-   $themes = array();
-   if ($theme_name) {
-     $themes = array($theme_name);
-   }
-   else {
-     foreach (list_themes() as $key => $data) {
-       if ($data->status) {
-         $themes[] = $key;
-       }
-     }
-   }
- 
-   foreach ($themes as $theme) {
-     $theme_config_name = $theme . '.settings';
-     $theme_config = config($theme_config_name);
-     if ($theme_config && $new_color_config = $theme_config->get('color')) {
-       $color_info = color_get_info($theme);
-       if ($color_info) {
-         $palette = isset($new_color_config['palette']) ? $new_color_config['palette'] : NULL;
-         $new_color_info = color_save_configuration($theme, $color_info, $palette);
-         $theme_config->set('color', $new_color_info);
-         $theme_config->save();
-       }
-     }
-   }
- }
- 
-  * Generates the necessary CSS and images based on a color palette.
-  *
-  * @param $theme_name
-  *   The theme machine name.
-  * @param $theme_info
-  *   The theme info, as loaded by list_themes().
-  * @param $palette
-  *   The color palette on which the images and CSS will be generated.
-  *
-  * @return array|NULL
-  *   Returns an array of values to be saved in the theme configuration. If no
-  *   color settings are necessary (such as when using the default color scheme),
-  *   NULL is returned.
-  */
- function color_save_configuration($theme_name, $theme_info, $palette) {
-   
-   $files = theme_get_setting('color.files', $theme_name);
-   if ($files) {
-     foreach ($files as $file) {
-       @backdrop_unlink($file);
-     }
-   }
-   if (isset($file) && $file = dirname($file)) {
-     @backdrop_rmdir($file);
-   }
- 
-   
-   if (empty($palette) || implode(',', color_get_palette($theme_name, TRUE)) == implode(',', $palette)) {
-     return NULL;
-   }
- 
-   
-   $id = $theme_name . '-' . substr(hash('sha256', serialize($palette) . microtime()), 0, 8);
-   $paths['color'] = 'public://color';
-   $paths['target'] = $paths['color'] . '/' . $id;
-   foreach ($paths as $path) {
-     file_prepare_directory($path, FILE_CREATE_DIRECTORY);
-   }
-   $paths['target'] = $paths['target'] . '/';
-   $paths['id'] = $id;
-   $paths['source'] = backdrop_get_path('theme', $theme_name) . '/';
-   $paths['files'] = $paths['map'] = array();
- 
-   
-   $css = array();
-   foreach ($theme_info['css'] as $stylesheet) {
-     
-     $files = array();
-     $filename = _color_get_file_path($stylesheet, $theme_name);
-     if (file_exists($filename)) {
-       $files[] = $stylesheet;
-     }
- 
-     foreach ($files as $file) {
-       
-       
-       
-       $filename = _color_get_file_path($file, $theme_name);
-       $theme = _color_get_theme_from_file($file, $theme_name);
-       $paths['source'] = backdrop_get_path('theme', $theme) . '/';
- 
-       $style = backdrop_load_stylesheet($filename, FALSE);
- 
-       
-       
-       $base = base_path() . dirname($filename) . '/';
-       _backdrop_build_css_path(NULL, $base);
- 
-       
-       $style = preg_replace_callback('/url\([\'"]?(?![a-z]+:|\/+)([^\'")]+)[\'"]?\)/i', '_backdrop_build_css_path', $style);
- 
-       
-       $style = _color_rewrite_stylesheet($theme_name, $theme_info, $paths, $palette, $style);
-       $base_file = backdrop_basename($file);
-       $css[] = $paths['target'] . $base_file;
-       _color_save_stylesheet($paths['target'] . $base_file, $style, $paths);
-     }
-   }
- 
-   return array(
-     'palette' => $palette,
-     'stylesheets' => $css,
-     'files' => $paths['files'],
-   );
- }
- 
-  * Rewrites the stylesheet to match the colors in the palette.
-  */
- function _color_rewrite_stylesheet($theme, &$info, &$paths, $palette, $style) {
-   
-   $conversion = $palette;
-   foreach ($conversion as $k => $v) {
-     $conversion[$k] = backdrop_strtolower($v);
-   }
-   $default = color_get_palette($theme, TRUE);
-   
-   $split = "Color Module: Don't touch";
-   if (strpos($style, $split) !== FALSE) {
-     list($style, $fixed) = explode($split, $style);
-   }
- 
-   
-   $style = preg_split('/(#[0-9a-f]{6}|#[0-9a-f]{3})/i', $style, -1, PREG_SPLIT_DELIM_CAPTURE);
-   $is_color = FALSE;
-   $output = '';
-   $base = 'base';
- 
-   
-   foreach ($style as $chunk) {
-     if ($is_color) {
-       $chunk = backdrop_strtolower($chunk);
-       
-       if (backdrop_strlen($chunk) == 4) {
-         $chunk = '#' . $chunk[1] . $chunk[1] . $chunk[2] . $chunk[2] . $chunk[3] . $chunk[3];
-       }
-       
-       if ($key = array_search($chunk, $default)) {
-         $chunk = $conversion[$key];
-       }
-       
-       else {
-         if (isset($info['blend_target'])) {
-           $chunk = _color_shift($palette[$base], $default[$base], $chunk, $info['blend_target']);
-         }
-       }
-     }
-     else {
-       
- 
-       
-       if (preg_match('@[^a-z0-9_-](a)[^a-z0-9_-][^/{]*{[^{]+$@i', $chunk)) {
-         $base = 'link';
-       }
-       
-       elseif (preg_match('/(?<!-)color[^{:]*:[^{#]*$/i', $chunk)) {
-         $base = 'text';
-       }
-       
-       else {
-         $base = 'base';
-       }
-     }
-     $output .= $chunk;
-     $is_color = !$is_color;
-   }
-   
-   if (isset($fixed)) {
-     $output .= $fixed;
-   }
- 
-   
-   foreach ($paths['map'] as $before => $after) {
-     $before = base_path() . $paths['source'] . $before;
-     $before = preg_replace('`(^|/)(?!../)([^/]+)/../`', '$1', $before);
-     $output = str_replace($before, $after, $output);
-   }
- 
-   return $output;
- }
- 
-  * Saves the rewritten stylesheet to disk.
-  */
- function _color_save_stylesheet($file, $style, &$paths) {
-   $filepath = file_unmanaged_save_data($style, $file, FILE_EXISTS_REPLACE);
-   $paths['files'][] = $filepath;
- 
-   
-   backdrop_chmod($file);
- }
- 
-  * Finds the original file path of a CSS file from the color configuration.
-  *
-  * @param $filename
-  *   The file name that we are searching for.
-  * @param $theme_name
-  *   The name of the theme that is being modified.
-  *
-  * @return string
-  *   Returns the original file path of the CSS file.
-  */
- function _color_get_file_path($filename, $theme_name) {
-   static $basenames = array();
- 
-   $themes = list_themes();
-   $theme = $themes[$theme_name];
- 
-   $basename = backdrop_basename($filename);
- 
-   if (isset($theme->stylesheets)) {
-     foreach ($theme->stylesheets as $group_name => $group) {
-       foreach ($group as $file) {
-         if (!isset($basenames[$theme_name][$group_name][$file])) {
-           $basenames[$theme_name][$group_name][$file] = backdrop_basename($file);
-         }
-         if ($basename === $basenames[$theme_name][$group_name][$file]) {
-           return $file;
-         }
-       }
-     }
-   }
- 
-   if (isset($theme->base_theme)) {
-     return _color_get_file_path($filename, $theme->base_theme);
-   }
- }
- 
-  * Finds which theme a CSS file came from.
-  *
-  * @param $filename
-  *   The file name that we are searching for.
-  * @param $theme_name
-  *   The name of the theme that is being modified.
-  *
-  * @return string
-  *   Returns the name of the theme that the CSS file came from.
-  */
- function _color_get_theme_from_file($filename, $theme_name) {
-   $themes = list_themes();
-   $theme = $themes[$theme_name];
- 
-   $basename = backdrop_basename($filename);
- 
-   if (isset($theme->stylesheets)) {
-     foreach ($theme->stylesheets as $group_name => $group) {
-       foreach ($group as $file) {
-         if ($basename === backdrop_basename($file)) {
-           return $theme_name;
-         }
-       }
-     }
-   }
- 
-   if (isset($theme->base_theme)) {
-     return _color_get_theme_from_file($filename, $theme->base_theme);
-   }
- }
- 
-  * Shifts a given color, using a reference pair and a target blend color.
-  *
-  * Note: this function is significantly different from the JS version, as it
-  * is written to match the blended images perfectly.
-  *
-  * Constraint: if (ref2 == target + (ref1 - target) * delta) for some fraction
-  * delta then (return == target + (given - target) * delta).
-  *
-  * Loose constraint: Preserve relative positions in saturation and luminance
-  * space.
-  */
- function _color_shift($given, $ref1, $ref2, $target) {
-   
-   
- 
-   
-   $target = _color_unpack($target, TRUE);
-   $ref1 = _color_unpack($ref1, TRUE);
-   $ref2 = _color_unpack($ref2, TRUE);
-   $numerator = 0;
-   $denominator = 0;
-   for ($i = 0; $i < 3; ++$i) {
-     $numerator += ($ref2[$i] - $ref1[$i]) * ($ref2[$i] - $ref1[$i]);
-     $denominator += ($target[$i] - $ref1[$i]) * ($target[$i] - $ref1[$i]);
-   }
-   $delta = ($denominator > 0) ? (1 - sqrt($numerator / $denominator)) : 0;
- 
-   
-   for ($i = 0; $i < 3; ++$i) {
-     $ref3[$i] = $target[$i] + ($ref1[$i] - $target[$i]) * $delta;
-   }
- 
-   
-   
-   $ref2 = _color_rgb2hsl($ref2);
-   $ref3 = _color_rgb2hsl($ref3);
-   for ($i = 0; $i < 3; ++$i) {
-     $shift[$i] = $ref2[$i] - $ref3[$i];
-   }
- 
-   
-   $given = _color_unpack($given, TRUE);
-   for ($i = 0; $i < 3; ++$i) {
-     $result[$i] = $target[$i] + ($given[$i] - $target[$i]) * $delta;
-   }
- 
-   
-   
-   $result = _color_rgb2hsl($result);
-   for ($i = 0; $i < 3; ++$i) {
-     $result[$i] = min(1, max(0, $result[$i] + $shift[$i]));
-   }
-   $result = _color_hsl2rgb($result);
- 
-   
-   return _color_pack($result, TRUE);
- }
- 
-  * Converts a hex color into an RGB triplet.
-  */
- function _color_unpack($hex, $normalize = FALSE) {
-   $hex = substr($hex, 1);
-   if (strlen($hex) == 3) {
-     $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
-   }
-   $c = hexdec($hex);
-   for ($i = 16; $i >= 0; $i -= 8) {
-     $out[] = (($c >> $i) & 0xFF) / ($normalize ? 255 : 1);
-   }
- 
-   return $out;
- }
- 
-  * Converts an RGB triplet to a hex color.
-  */
- function _color_pack($rgb, $normalize = FALSE) {
-   $out = 0;
-   foreach ($rgb as $k => $v) {
-     $out |= (((int) $v * ($normalize ? 255 : 1)) << (16 - $k * 8));
-   }
- 
-   return '#' . str_pad(dechex($out), 6, 0, STR_PAD_LEFT);
- }
- 
-  * Converts an HSL triplet into RGB.
-  */
- function _color_hsl2rgb($hsl) {
-   $h = $hsl[0];
-   $s = $hsl[1];
-   $l = $hsl[2];
-   $m2 = ($l <= 0.5) ? $l * ($s + 1) : $l + $s - $l*$s;
-   $m1 = $l * 2 - $m2;
- 
-   return array(
-     _color_hue2rgb($m1, $m2, $h + 0.33333),
-     _color_hue2rgb($m1, $m2, $h),
-     _color_hue2rgb($m1, $m2, $h - 0.33333),
-   );
- }
- 
-  * Helper function for _color_hsl2rgb().
-  */
- function _color_hue2rgb($m1, $m2, $h) {
-   $h = ($h < 0) ? $h + 1 : (($h > 1) ? $h - 1 : $h);
-   if ($h * 6 < 1) return $m1 + ($m2 - $m1) * $h * 6;
-   if ($h * 2 < 1) return $m2;
-   if ($h * 3 < 2) return $m1 + ($m2 - $m1) * (0.66666 - $h) * 6;
- 
-   return $m1;
- }
- 
-  * Converts an RGB triplet to HSL.
-  */
- function _color_rgb2hsl($rgb) {
-   $r = $rgb[0];
-   $g = $rgb[1];
-   $b = $rgb[2];
-   $min = min($r, min($g, $b));
-   $max = max($r, max($g, $b));
-   $delta = $max - $min;
-   $l = ($min + $max) / 2;
-   $s = 0;
- 
-   if ($l > 0 && $l < 1) {
-     $s = $delta / ($l < 0.5 ? (2 * $l) : (2 - 2 * $l));
-   }
- 
-   $h = 0;
-   if ($delta > 0) {
-     if ($max == $r && $max != $g) $h += ($g - $b) / $delta;
-     if ($max == $g && $max != $b) $h += (2 + ($b - $r) / $delta);
-     if ($max == $b && $max != $r) $h += (4 + ($r - $g) / $delta);
-     $h /= 6;
-   }
- 
-   return array($h, $s, $l);
- }