envs = config.get('<STR_LIT>', {}).get('<STR_LIT>', [])<EOL>out("<STR_LIT>")<EOL>for name, conf in list(envs.items()):<EOL><INDENT>out('<STR_LIT:\t>'+name)<EOL><DEDENT>envs = helper.get_environments()<EOL>out("<STR_LIT>")<EOL>for env in envs:<EOL><INDENT>if env['<STR_LIT>'] != '<STR_LIT>':<EOL><INDENT>out('<STR_LIT:\t>'+str(env['<STR_LIT>'])+'<STR_LIT>'+str(env['<STR_LIT>'])+'<STR_LIT:U+002CU+0020>'+str(env['<STR_LIT>'])+'<STR_LIT:)>')<EOL><DEDENT><DEDENT>


versions = helper.get_versions()<EOL>out("<STR_LIT>")<EOL>for version in versions:<EOL><INDENT>out(version)<EOL><DEDENT>


parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', required=True)<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', action='<STR_LIT:store_true>')<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', required=False)<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', required=False)<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', required=False)<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>',<EOL>required=False, action='<STR_LIT:store_true>')<EOL>


version_label = args.version_label<EOL>env_config = parse_env_config(config, args.environment)<EOL>env_name = args.environment<EOL>version_label = upload_application_archive(<EOL>helper, env_config, archive=args.archive,<EOL>directory=args.directory, version_label=version_label)<EOL>import datetime<EOL>start_time = datetime.datetime.utcnow().isoformat() + '<STR_LIT>'<EOL>helper.deploy_version(env_name, version_label)<EOL>if not args.dont_wait:<EOL><INDENT>helper.wait_for_environments(env_name, status='<STR_LIT>',<EOL>version_label=version_label,<EOL>include_deleted=False)<EOL><DEDENT>env = parse_env_config(config, env_name)<EOL>option_settings = parse_option_settings(env.get('<STR_LIT>', {}))<EOL>helper.update_environment(env_name,<EOL>description=env.get('<STR_LIT:description>', None),<EOL>option_settings=option_settings,<EOL>tier_type=env.get('<STR_LIT>'),<EOL>tier_name=env.get('<STR_LIT>'),<EOL>tier_version=env.get('<STR_LIT>'))<EOL>if not args.dont_wait:<EOL><INDENT>helper.wait_for_environments(env_name, health='<STR_LIT>',<EOL>status='<STR_LIT>', version_label=version_label,<EOL>include_deleted=False)<EOL><DEDENT>events = helper.ebs.describe_events(start_time=start_time, environment_name=env_name)<EOL>import json<EOL>if args.log_events_to_file:<EOL><INDENT>with open('<STR_LIT>', '<STR_LIT>') as f:<EOL><INDENT>json.dump(events, f)<EOL><DEDENT><DEDENT>helper.delete_unused_versions(versions_to_keep=int(get(config, '<STR_LIT>', <NUM_LIT:10>)))<EOL>


parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', required=True)<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', required=True)<EOL>

adds arguments for the describe events command


helper.wait_for_environments(args.environment, health=args.health)<EOL>


parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', required=True)<EOL>


env = parse_env_config(config, args.environment)<EOL>option_settings = env.get('<STR_LIT>', {})<EOL>settings = parse_option_settings(option_settings)<EOL>for setting in settings:<EOL><INDENT>out(str(setting))<EOL><DEDENT>


ret = []<EOL>for f in os.listdir(COMMAND_MODULE_PATH):<EOL><INDENT>if os.path.isfile(os.path.join(COMMAND_MODULE_PATH, f)) and f.endswith(COMMAND_MODULE_SUFFIX):<EOL><INDENT>ret.append(f[:-len(COMMAND_MODULE_SUFFIX)])<EOL><DEDENT><DEDENT>return ret<EOL>

Returns a list of command names supported


try:<EOL><INDENT>result = get_command_without_error_checking(name)<EOL><DEDENT>except:<EOL><INDENT>result = get_command_without_error_checking('<STR_LIT>')<EOL><DEDENT>return result<EOL>


__import__('<STR_LIT>' + name + '<STR_LIT>')<EOL>return sys.modules['<STR_LIT>' + name + '<STR_LIT>']<EOL>


parser.add_argument('<STR_LIT>', '<STR_LIT>',      help='<STR_LIT>', required=True)<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>',        help='<STR_LIT>', action='<STR_LIT:store_true>')<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>',    help='<STR_LIT>', required=False)<EOL>


env_config = parse_env_config(config, args.environment)<EOL>cname_prefix = env_config.get('<STR_LIT>', None)<EOL>env_name = args.environment<EOL>if args.version_label:<EOL><INDENT>helper.deploy_version(env_name, args.version_label)<EOL>if not args.dont_wait:<EOL><INDENT>helper.wait_for_environments(env_name, status='<STR_LIT>', version_label=args.version_label)<EOL><DEDENT><DEDENT>env = parse_env_config(config, env_name)<EOL>option_settings = parse_option_settings(env.get('<STR_LIT>', {}))<EOL>helper.update_environment(env_name,<EOL>description=env.get('<STR_LIT:description>', None),<EOL>option_settings=option_settings,<EOL>tier_type=env.get('<STR_LIT>'),<EOL>tier_name=env.get('<STR_LIT>'),<EOL>tier_version=env.get('<STR_LIT>'))<EOL>if not args.dont_wait:<EOL><INDENT>helper.wait_for_environments(env_name, health='<STR_LIT>', status='<STR_LIT>', version_label=args.version_label)<EOL><DEDENT>helper.delete_unused_versions(versions_to_keep=int( get(config, '<STR_LIT>', <NUM_LIT:10>) ))<EOL>


parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', required=True)<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', action='<STR_LIT:store_true>')<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', required=False)<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', required=False)<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', required=False)<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>',<EOL>help='<STR_LIT>',<EOL>type=int, required=False)<EOL>


version_label = args.version_label<EOL>archive = args.archive<EOL>env_config = parse_env_config(config, args.environment)<EOL>option_settings = parse_option_settings(env_config.get('<STR_LIT>', {}))<EOL>cname_prefix = env_config.get('<STR_LIT>', None)<EOL>tier_name = env_config.get('<STR_LIT>', '<STR_LIT>')<EOL>if tier_name != '<STR_LIT>':<EOL><INDENT>raise Exception(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>" % (tier_name, ))<EOL><DEDENT>out("<STR_LIT>")<EOL>new_env_name = None<EOL>if not helper.environment_exists(args.environment):<EOL><INDENT>new_env_name = args.environment<EOL><DEDENT>else:<EOL><INDENT>for i in range(<NUM_LIT:10>):<EOL><INDENT>temp_env_name = args.environment + '<STR_LIT:->' + str(i)<EOL>if not helper.environment_exists(temp_env_name):<EOL><INDENT>new_env_name = temp_env_name<EOL>break<EOL><DEDENT><DEDENT><DEDENT>if new_env_name is None:<EOL><INDENT>raise Exception("<STR_LIT>")<EOL><DEDENT>out("<STR_LIT>" + new_env_name)<EOL>out("<STR_LIT>")<EOL>new_env_cname = None<EOL>for i in range(<NUM_LIT:10>):<EOL><INDENT>temp_cname = cname_prefix + '<STR_LIT:->' + str(i)<EOL>if not helper.environment_name_for_cname(temp_cname):<EOL><INDENT>new_env_cname = temp_cname<EOL>break<EOL><DEDENT><DEDENT>if new_env_cname is None:<EOL><INDENT>raise Exception("<STR_LIT>")<EOL><DEDENT>out("<STR_LIT>" + new_env_cname)<EOL>version_label = upload_application_archive(<EOL>helper, env_config, archive=args.archive, directory=args.directory, version_label=version_label)<EOL>helper.create_environment(new_env_name,<EOL>solution_stack_name=env_config.get('<STR_LIT>'),<EOL>cname_prefix=new_env_cname,<EOL>description=env_config.get('<STR_LIT:description>', None),<EOL>option_settings=option_settings,<EOL>version_label=version_label,<EOL>tier_name=tier_name,<EOL>tier_type=env_config.get('<STR_LIT>'),<EOL>tier_version=env_config.get('<STR_LIT>'))<EOL>helper.wait_for_environments(new_env_name, status='<STR_LIT>', health='<STR_LIT>', include_deleted=False)<EOL>old_env_name = helper.environment_name_for_cname(cname_prefix)<EOL>if old_env_name is None:<EOL><INDENT>raise Exception("<STR_LIT>" + cname_prefix)<EOL><DEDENT>out("<STR_LIT>" + old_env_name)<EOL>out("<STR_LIT>")<EOL>helper.swap_environment_cnames(old_env_name, new_env_name)<EOL>helper.wait_for_environments([old_env_name, new_env_name], status='<STR_LIT>', include_deleted=False)<EOL>if args.termination_delay:<EOL><INDENT>out("<STR_LIT>".format(args.termination_delay))<EOL>time.sleep(args.termination_delay)<EOL><DEDENT>out("<STR_LIT>".format(old_env_name))<EOL>helper.delete_environment(old_env_name)<EOL>helper.delete_unused_versions(versions_to_keep=int(get(config, '<STR_LIT>', <NUM_LIT:10>)))<EOL>


out("<STR_LIT>")<EOL>for stack in helper.list_available_solution_stacks():<EOL><INDENT>out("<STR_LIT:U+0020>"+str(stack))<EOL><DEDENT>return <NUM_LIT:0><EOL>


parser.add_argument('<STR_LIT>', '<STR_LIT>',<EOL>help='<STR_LIT>', required=True)<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>',<EOL>help='<STR_LIT>',<EOL>action='<STR_LIT:store_true>')<EOL>


env_config = parse_env_config(config, args.environment)<EOL>environments_to_wait_for_term = []<EOL>environments = helper.get_environments()<EOL>for env in environments:<EOL><INDENT>if env['<STR_LIT>'] == args.environment:<EOL><INDENT>if env['<STR_LIT>'] != '<STR_LIT>':<EOL><INDENT>out("<STR_LIT>" + env['<STR_LIT>']<EOL>+ "<STR_LIT>"<EOL>+ env['<STR_LIT>'] + "<STR_LIT:)>")<EOL><DEDENT>else:<EOL><INDENT>out("<STR_LIT>"+env['<STR_LIT>'])<EOL>helper.delete_environment(env['<STR_LIT>'])<EOL>environments_to_wait_for_term.append(env['<STR_LIT>'])<EOL><DEDENT><DEDENT><DEDENT>if not args.dont_wait:<EOL><INDENT>helper.wait_for_environments(environments_to_wait_for_term,<EOL>status='<STR_LIT>',<EOL>include_deleted=True)<EOL><DEDENT>out("<STR_LIT>")<EOL>return <NUM_LIT:0><EOL>


parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', action='<STR_LIT:store_true>')<EOL>


helper.delete_application()<EOL>if not args.dont_wait:<EOL><INDENT>environment_names = []<EOL>for env in helper.get_environments():<EOL><INDENT>environment_names.append(env['<STR_LIT>'])<EOL><DEDENT>helper.wait_for_environments(environment_names, status='<STR_LIT>')<EOL><DEDENT>return <NUM_LIT:0><EOL>


parser.add_argument('<STR_LIT>', '<STR_LIT>',  help='<STR_LIT>', required=False, nargs='<STR_LIT:+>')<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', action='<STR_LIT:store_true>')<EOL>


environments = []<EOL>if args.environment:<EOL><INDENT>for env_name in args.environment:<EOL><INDENT>environments.append(env_name)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>for env_name, env_config in list(get(config, '<STR_LIT>').items()):<EOL><INDENT>environments.append(env_name)<EOL><DEDENT><DEDENT>wait_environments = []<EOL>for env_name in environments:<EOL><INDENT>env = parse_env_config(config, env_name)<EOL>option_settings = parse_option_settings(env.get('<STR_LIT>', {}))<EOL>helper.update_environment(env_name,<EOL>description=env.get('<STR_LIT:description>', None),<EOL>option_settings=option_settings,<EOL>tier_type=env.get('<STR_LIT>'),<EOL>tier_name=env.get('<STR_LIT>'),<EOL>tier_version=env.get('<STR_LIT>'))<EOL>wait_environments.append(env_name)<EOL><DEDENT>if not args.dont_wait:<EOL><INDENT>helper.wait_for_environments(wait_environments, health='<STR_LIT>', status='<STR_LIT>')<EOL><DEDENT>


parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', action='<STR_LIT:store_true>')<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', action='<STR_LIT:store_true>')<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', default=None)<EOL>


<EOL>if not helper.application_exists():<EOL><INDENT>helper.create_application(get(config, '<STR_LIT>'))<EOL><DEDENT>else:<EOL><INDENT>out("<STR_LIT>"+get(config, '<STR_LIT>')+"<STR_LIT>")<EOL><DEDENT>environment_names = []<EOL>environments_to_wait_for_green = []<EOL>for env_name, env_config in list(get(config, '<STR_LIT>').items()):<EOL><INDENT>environment_names.append(env_name)<EOL>env_config = parse_env_config(config, env_name)<EOL>if not helper.environment_exists(env_name):<EOL><INDENT>option_settings = parse_option_settings(env_config.get('<STR_LIT>', {}))<EOL>helper.create_environment(env_name,<EOL>solution_stack_name=env_config.get('<STR_LIT>'),<EOL>cname_prefix=env_config.get('<STR_LIT>', None),<EOL>description=env_config.get('<STR_LIT:description>', None),<EOL>option_settings=option_settings,<EOL>tier_name=env_config.get('<STR_LIT>'),<EOL>tier_type=env_config.get('<STR_LIT>'),<EOL>tier_version=env_config.get('<STR_LIT>'),<EOL>version_label=args.version_label)<EOL>environments_to_wait_for_green.append(env_name)<EOL><DEDENT>else:<EOL><INDENT>out("<STR_LIT>"+env_name)<EOL><DEDENT><DEDENT>environments_to_wait_for_term = []<EOL>if args.delete:<EOL><INDENT>environments = helper.get_environments()<EOL>for env in environments:<EOL><INDENT>if env['<STR_LIT>'] not in environment_names:<EOL><INDENT>if env['<STR_LIT>'] != '<STR_LIT>':<EOL><INDENT>out("<STR_LIT>"+env['<STR_LIT>']+"<STR_LIT>"+env['<STR_LIT>']+"<STR_LIT:)>")<EOL><DEDENT>else:<EOL><INDENT>out("<STR_LIT>"+env['<STR_LIT>'])<EOL>helper.delete_environment(env['<STR_LIT>'])<EOL>environments_to_wait_for_term.append(env['<STR_LIT>'])<EOL><DEDENT><DEDENT><DEDENT><DEDENT>if not args.dont_wait and len(environments_to_wait_for_green)><NUM_LIT:0>:<EOL><INDENT>helper.wait_for_environments(environments_to_wait_for_green, status='<STR_LIT>', include_deleted=False)<EOL><DEDENT>if not args.dont_wait and len(environments_to_wait_for_term)><NUM_LIT:0>:<EOL><INDENT>helper.wait_for_environments(environments_to_wait_for_term, status='<STR_LIT>', include_deleted=False)<EOL><DEDENT>out("<STR_LIT>")<EOL>return <NUM_LIT:0><EOL>


parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', required=True)<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', required=True)<EOL>

adds arguments for the swap urls command


old_env_name = args.old_environment<EOL>new_env_name = args.new_environment<EOL>out("<STR_LIT>".format(old_env_name))<EOL>out("<STR_LIT>".format(new_env_name,<EOL>old_env_name))<EOL>helper.swap_environment_cnames(old_env_name, new_env_name)<EOL>helper.wait_for_environments([old_env_name, new_env_name], status='<STR_LIT>', include_deleted=False)<EOL>

Swaps old and new URLs.
If old_environment was active, new_environment will become the active environment


parser.add_argument('<STR_LIT>', '<STR_LIT>', help='<STR_LIT>', required=True)<EOL>


environment_name = args.environment<EOL>(events, next_token) = helper.describe_events(environment_name, start_time=datetime.now().isoformat())<EOL>for event in events:<EOL><INDENT>print(("<STR_LIT:[>"+event['<STR_LIT>']+"<STR_LIT>"+event['<STR_LIT>']))<EOL><DEDENT>

Describes recent events for an environment.


sys.stdout.write(message + "<STR_LIT:\n>")<EOL>sys.stdout.flush()<EOL>


val = vals<EOL>for part in key.split('<STR_LIT:.>'):<EOL><INDENT>if isinstance(val, dict):<EOL><INDENT>val = val.get(part, None)<EOL>if val is None:<EOL><INDENT>return default_val<EOL><DEDENT><DEDENT>else:<EOL><INDENT>return default_val<EOL><DEDENT><DEDENT>return val<EOL>


ret = []<EOL>for namespace, params in list(option_settings.items()):<EOL><INDENT>for key, value in list(params.items()):<EOL><INDENT>ret.append((namespace, key, value))<EOL><DEDENT><DEDENT>return ret<EOL>

Parses option_settings as they are defined in the configuration file


all_env = get(config, '<STR_LIT>', {})<EOL>env = get(config, '<STR_LIT>' + str(env_name), {})<EOL>return merge_dict(all_env, env)<EOL>


def create_archive(directory, filename, config={}, ignore_predicate=None, ignored_files=['<STR_LIT>', '<STR_LIT>']):

with zipfile.ZipFile(filename, '<STR_LIT:w>', compression=zipfile.ZIP_DEFLATED) as zip_file:<EOL><INDENT>root_len = len(os.path.abspath(directory))<EOL>out("<STR_LIT>" + str(filename))<EOL>for root, dirs, files in os.walk(directory, followlinks=True):<EOL><INDENT>archive_root = os.path.abspath(root)[root_len + <NUM_LIT:1>:]<EOL>for f in files:<EOL><INDENT>fullpath = os.path.join(root, f)<EOL>archive_name = os.path.join(archive_root, f)<EOL>if filename in fullpath:<EOL><INDENT>continue<EOL><DEDENT>if ignored_files is not None:<EOL><INDENT>for name in ignored_files:<EOL><INDENT>if fullpath.endswith(name):<EOL><INDENT>out("<STR_LIT>" + str(name))<EOL>continue<EOL><DEDENT><DEDENT><DEDENT>if ignore_predicate is not None:<EOL><INDENT>if not ignore_predicate(archive_name):<EOL><INDENT>out("<STR_LIT>" + str(archive_name))<EOL>continue<EOL><DEDENT><DEDENT>out("<STR_LIT>" + str(archive_name))<EOL>zip_file.write(fullpath, archive_name, zipfile.ZIP_DEFLATED)<EOL><DEDENT><DEDENT><DEDENT>return filename<EOL>

Creates an archive from a directory and returns
the file that was created.


def add_config_files_to_archive(directory, filename, config={}):

with zipfile.ZipFile(filename, '<STR_LIT:a>') as zip_file:<EOL><INDENT>for conf in config:<EOL><INDENT>for conf, tree in list(conf.items()):<EOL><INDENT>if '<STR_LIT>' in tree:<EOL><INDENT>content = yaml.dump(tree['<STR_LIT>'], default_flow_style=False)<EOL><DEDENT>else:<EOL><INDENT>content = tree.get('<STR_LIT:content>', '<STR_LIT>')<EOL><DEDENT>out("<STR_LIT>" + str(conf) + "<STR_LIT>" + str(filename))<EOL>file_entry = zipfile.ZipInfo(conf)<EOL>file_entry.external_attr = tree.get('<STR_LIT>', <NUM_LIT>) << <NUM_LIT:16> <EOL>zip_file.writestr(file_entry, content)<EOL><DEDENT><DEDENT><DEDENT>return filename<EOL>

Adds configuration files to an existing archive


def __init__(self, aws, wait_time_secs, app_name=None,):

self.aws = aws<EOL>self.ebs = connect_to_region(aws.region, aws_access_key_id=aws.access_key,<EOL>aws_secret_access_key=aws.secret_key,<EOL>security_token=aws.security_token)<EOL>self.s3 = S3Connection(<EOL>aws_access_key_id=aws.access_key, <EOL>aws_secret_access_key=aws.secret_key, <EOL>security_token=aws.security_token,<EOL>host=(lambda r: '<STR_LIT>' if r == '<STR_LIT>' else '<STR_LIT>' + r + '<STR_LIT>')(aws.region))<EOL>self.app_name = app_name<EOL>self.wait_time_secs = wait_time_secs<EOL>


def swap_environment_cnames(self, from_env_name, to_env_name):

self.ebs.swap_environment_cnames(source_environment_name=from_env_name,<EOL>destination_environment_name=to_env_name)<EOL>


def upload_archive(self, filename, key, auto_create_bucket=True):

try:<EOL><INDENT>bucket = self.s3.get_bucket(self.aws.bucket)<EOL>if ((<EOL>self.aws.region != '<STR_LIT>' and self.aws.region != '<STR_LIT>') and bucket.get_location() != self.aws.region) or (<EOL>self.aws.region == '<STR_LIT>' and bucket.get_location() != '<STR_LIT>') or (<EOL>self.aws.region == '<STR_LIT>' and bucket.get_location() != '<STR_LIT>'):<EOL><INDENT>raise Exception("<STR_LIT>")<EOL><DEDENT><DEDENT>except S3ResponseError:<EOL><INDENT>bucket = self.s3.create_bucket(self.aws.bucket, location=self.aws.region)<EOL><DEDENT>def __report_upload_progress(sent, total):<EOL><INDENT>if not sent:<EOL><INDENT>sent = <NUM_LIT:0><EOL><DEDENT>if not total:<EOL><INDENT>total = <NUM_LIT:0><EOL><DEDENT>out("<STR_LIT>" + str(sent) + "<STR_LIT>" + str(total)+ "<STR_LIT>" + str(int(float(max(<NUM_LIT:1>, sent)) / float(total) * <NUM_LIT:100>)) + "<STR_LIT>")<EOL><DEDENT>k = Key(bucket)<EOL>k.key = self.aws.bucket_path + key<EOL>k.set_metadata('<STR_LIT:time>', str(time()))<EOL>k.set_contents_from_filename(filename, cb=__report_upload_progress, num_cb=<NUM_LIT:10>)<EOL>

Uploads an application archive version to s3


stacks = self.ebs.list_available_solution_stacks()<EOL>return stacks['<STR_LIT>']['<STR_LIT>']['<STR_LIT>']<EOL>

Returns a list of available solution stacks


out("<STR_LIT>" + str(self.app_name))<EOL>self.ebs.create_application(self.app_name, description=description)<EOL>

Creats an application and sets the helpers current
app_name to the created application


out("<STR_LIT>" + str(self.app_name))<EOL>self.ebs.delete_application(self.app_name, terminate_env_by_force=True)<EOL>


response = self.ebs.describe_applications(application_names=[self.app_name])<EOL>return len(response['<STR_LIT>']['<STR_LIT>']['<STR_LIT>']) > <NUM_LIT:0><EOL>

Returns whether or not the given app_name exists


def create_environment(self, env_name, version_label=None,<EOL>solution_stack_name=None, cname_prefix=None, description=None,<EOL>option_settings=None, tier_name='<STR_LIT>', tier_type='<STR_LIT>', tier_version='<STR_LIT>'):

out("<STR_LIT>" + str(env_name) + "<STR_LIT>" + str(tier_name) + "<STR_LIT>" + str(tier_type))<EOL>self.ebs.create_environment(self.app_name, env_name,<EOL>version_label=version_label,<EOL>solution_stack_name=solution_stack_name,<EOL>cname_prefix=cname_prefix,<EOL>description=description,<EOL>option_settings=option_settings,<EOL>tier_type=tier_type,<EOL>tier_name=tier_name,<EOL>tier_version=tier_version)<EOL>


response = self.ebs.describe_environments(application_name=self.app_name, environment_names=[env_name],<EOL>include_deleted=False)<EOL>return len(response['<STR_LIT>']['<STR_LIT>']['<STR_LIT>']) > <NUM_LIT:0>and response['<STR_LIT>']['<STR_LIT>']['<STR_LIT>'][<NUM_LIT:0>][<EOL>'<STR_LIT>'] != '<STR_LIT>'<EOL>

Returns whether or not the given environment exists


out("<STR_LIT>" + str(env_name))<EOL>self.ebs.rebuild_environment(environment_name=env_name)<EOL>


response = self.ebs.describe_environments(application_name=self.app_name, include_deleted=False)<EOL>return response['<STR_LIT>']['<STR_LIT>']['<STR_LIT>']<EOL>


self.ebs.terminate_environment(environment_name=environment_name, terminate_resources=True)<EOL>


def update_environment(self, environment_name, description=None, option_settings=[], tier_type=None, tier_name=None,<EOL>tier_version='<STR_LIT:1.0>'):

out("<STR_LIT>" + str(environment_name))<EOL>messages = self.ebs.validate_configuration_settings(self.app_name, option_settings,<EOL>environment_name=environment_name)<EOL>messages = messages['<STR_LIT>']['<STR_LIT>']['<STR_LIT>']<EOL>ok = True<EOL>for message in messages:<EOL><INDENT>if message['<STR_LIT>'] == '<STR_LIT:error>':<EOL><INDENT>ok = False<EOL><DEDENT>out("<STR_LIT:[>" + message['<STR_LIT>'] + "<STR_LIT>" + str(environment_name) + "<STR_LIT>"+ message['<STR_LIT>'] + "<STR_LIT::>" + message['<STR_LIT>'] + "<STR_LIT>" + message['<STR_LIT>'])<EOL><DEDENT>self.ebs.update_environment(<EOL>environment_name=environment_name,<EOL>description=description,<EOL>option_settings=option_settings,<EOL>tier_type=tier_type,<EOL>tier_name=tier_name,<EOL>tier_version=tier_version)<EOL>


envs = self.get_environments()<EOL>for env in envs:<EOL><INDENT>if env['<STR_LIT>'] != '<STR_LIT>'and '<STR_LIT>' in envand env['<STR_LIT>']and env['<STR_LIT>'].lower().startswith(env_cname.lower() + '<STR_LIT:.>'):<EOL><INDENT>return env['<STR_LIT>']<EOL><DEDENT><DEDENT>return None<EOL>

Returns an environment name for the given cname


def deploy_version(self, environment_name, version_label):

out("<STR_LIT>" + str(version_label) + "<STR_LIT>" + str(environment_name))<EOL>self.ebs.update_environment(environment_name=environment_name, version_label=version_label)<EOL>


response = self.ebs.describe_application_versions(application_name=self.app_name)<EOL>return response['<STR_LIT>']['<STR_LIT>']['<STR_LIT>']<EOL>


def create_application_version(self, version_label, key):

out("<STR_LIT>" + str(version_label) + "<STR_LIT>" + str(key))<EOL>self.ebs.create_application_version(self.app_name, version_label,<EOL>s3_bucket=self.aws.bucket, s3_key=self.aws.bucket_path+key)<EOL>


<EOL>environments = self.ebs.describe_environments(application_name=self.app_name, include_deleted=False)<EOL>environments = environments['<STR_LIT>']['<STR_LIT>']['<STR_LIT>']<EOL>versions_in_use = []<EOL>for env in environments:<EOL><INDENT>versions_in_use.append(env['<STR_LIT>'])<EOL><DEDENT>versions = self.ebs.describe_application_versions(application_name=self.app_name)<EOL>versions = versions['<STR_LIT>']['<STR_LIT>'][<EOL>'<STR_LIT>']<EOL>versions = sorted(versions, reverse=True, key=functools.cmp_to_key(lambda x, y: (x['<STR_LIT>'] > y['<STR_LIT>']) - (x['<STR_LIT>'] < y['<STR_LIT>'])))<EOL>for version in versions[versions_to_keep:]:<EOL><INDENT>if version['<STR_LIT>'] in versions_in_use:<EOL><INDENT>out("<STR_LIT>" + version["<STR_LIT>"] + "<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>out("<STR_LIT>" + version["<STR_LIT>"])<EOL>self.ebs.delete_application_version(application_name=self.app_name,<EOL>version_label=version['<STR_LIT>'])<EOL>sleep(<NUM_LIT:2>)<EOL><DEDENT><DEDENT>


def describe_events(self, environment_name, next_token=None, start_time=None):

events = self.ebs.describe_events(<EOL>application_name=self.app_name,<EOL>environment_name=environment_name,<EOL>next_token=next_token,<EOL>start_time=start_time + '<STR_LIT>')<EOL>return (events['<STR_LIT>']['<STR_LIT>']['<STR_LIT>'], events['<STR_LIT>']['<STR_LIT>']['<STR_LIT>'])<EOL>

Describes events from the given environment


def wait_for_environments(self, environment_names, health=None, status=None, version_label=None,<EOL>include_deleted=True, use_events=True):

<EOL>if not isinstance(environment_names, (list, tuple)):<EOL><INDENT>environment_names = [environment_names]<EOL><DEDENT>environment_names = environment_names[:]<EOL>s = "<STR_LIT>" + ("<STR_LIT:U+002CU+0020>".join(environment_names)) + "<STR_LIT>"<EOL>if health is not None:<EOL><INDENT>s += "<STR_LIT>" + health<EOL><DEDENT>else:<EOL><INDENT>s += "<STR_LIT>"<EOL><DEDENT>if version_label is not None:<EOL><INDENT>s += "<STR_LIT>" + version_label<EOL><DEDENT>if status is not None:<EOL><INDENT>s += "<STR_LIT>" + status<EOL><DEDENT>out(s)<EOL>started = time()<EOL>seen_events = list()<EOL>for env_name in environment_names:<EOL><INDENT>(events, next_token) = self.describe_events(env_name, start_time=datetime.now().isoformat())<EOL>for event in events:<EOL><INDENT>seen_events.append(event)<EOL><DEDENT><DEDENT>while True:<EOL><INDENT>if len(environment_names) == <NUM_LIT:0>:<EOL><INDENT>break<EOL><DEDENT>sleep(<NUM_LIT:10>)<EOL>environments = self.ebs.describe_environments(<EOL>application_name=self.app_name,<EOL>environment_names=environment_names,<EOL>include_deleted=include_deleted)<EOL>environments = environments['<STR_LIT>']['<STR_LIT>']['<STR_LIT>']<EOL>if len(environments) <= <NUM_LIT:0>:<EOL><INDENT>raise Exception("<STR_LIT>")<EOL><DEDENT>for env in environments[:]:<EOL><INDENT>env_name = env['<STR_LIT>']<EOL>msg = "<STR_LIT>" + env_name + "<STR_LIT>" + str(env['<STR_LIT>'])<EOL>if version_label is not None:<EOL><INDENT>msg = msg + "<STR_LIT>" + str(env['<STR_LIT>'])<EOL><DEDENT>if status is not None:<EOL><INDENT>msg = msg + "<STR_LIT>" + str(env['<STR_LIT>'])<EOL><DEDENT>good_to_go = True<EOL>if health is not None:<EOL><INDENT>good_to_go = good_to_go and str(env['<STR_LIT>']) == health<EOL><DEDENT>if status is not None:<EOL><INDENT>good_to_go = good_to_go and str(env['<STR_LIT>']) == status<EOL><DEDENT>if version_label is not None:<EOL><INDENT>good_to_go = good_to_go and str(env['<STR_LIT>']) == version_label<EOL><DEDENT>if env['<STR_LIT>'] == '<STR_LIT>' and env['<STR_LIT>'] == '<STR_LIT>':<EOL><INDENT>if '<STR_LIT>' not in env:<EOL><INDENT>env['<STR_LIT>'] = <NUM_LIT:0><EOL><DEDENT>env['<STR_LIT>'] += <NUM_LIT:1><EOL>if env['<STR_LIT>'] > MAX_RED_SAMPLES:<EOL><INDENT>out('<STR_LIT>')<EOL>raise Exception('<STR_LIT>')<EOL><DEDENT><DEDENT>if good_to_go:<EOL><INDENT>out(msg + "<STR_LIT>")<EOL>environment_names.remove(env_name)<EOL><DEDENT>else:<EOL><INDENT>out(msg + "<STR_LIT>")<EOL><DEDENT>(events, next_token) = self.describe_events(env_name, start_time=datetime.now().isoformat())<EOL>for event in events:<EOL><INDENT>if event not in seen_events:<EOL><INDENT>out("<STR_LIT:[>"+event['<STR_LIT>']+"<STR_LIT>"+event['<STR_LIT>'])<EOL>seen_events.append(event)<EOL><DEDENT><DEDENT><DEDENT>elapsed = time() - started<EOL>if elapsed > self.wait_time_secs:<EOL><INDENT>message = "<STR_LIT>".format(<EOL>environments="<STR_LIT>".join(environment_names), health=(health or "<STR_LIT>")<EOL>)<EOL>raise Exception(message)<EOL><DEDENT><DEDENT>

Waits for an environment to have the given version_label
and to be in the green state


raise exception_class(message)<EOL>


def getSHA1(self, token, timestamp, nonce, encrypt):

try:<EOL><INDENT>sortlist = [token, timestamp, nonce, encrypt]<EOL>sortlist.sort()<EOL>sha = hashlib.sha1()<EOL>sha.update("<STR_LIT>".join(sortlist))<EOL>return WXBizMsgCrypt_OK, sha.hexdigest()<EOL><DEDENT>except Exception:<EOL><INDENT>return WXBizMsgCrypt_ComputeSignature_Error, None<EOL><DEDENT>

用SHA1算法生成安全签名
        @param token:  票据
        @param timestamp: 时间戳
        @param encrypt: 密文
        @param nonce: 随机字符串
        @return: 安全签名


try:<EOL><INDENT>xml_tree = ET.fromstring(xmltext)<EOL>encrypt = xml_tree.find("<STR_LIT>")<EOL>touser_name = xml_tree.find("<STR_LIT>")<EOL>if touser_name != None:<EOL><INDENT>touser_name = touser_name.text<EOL><DEDENT>return WXBizMsgCrypt_OK, encrypt.text, touser_name<EOL><DEDENT>except Exception:<EOL><INDENT>return WXBizMsgCrypt_ParseXml_Error, None, None<EOL><DEDENT>

提取出xml数据包中的加密消息
        @param xmltext: 待提取的xml字符串
        @return: 提取出的加密消息字符串


def generate(self, encrypt, signature, timestamp, nonce):

resp_dict = {<EOL>'<STR_LIT>': encrypt,<EOL>'<STR_LIT>': signature,<EOL>'<STR_LIT>': timestamp,<EOL>'<STR_LIT>': nonce,<EOL>}<EOL>resp_xml = self.AES_TEXT_RESPONSE_TEMPLATE % resp_dict<EOL>return resp_xml<EOL>

生成xml消息
        @param encrypt: 加密后的消息密文
        @param signature: 安全签名
        @param timestamp: 时间戳
        @param nonce: 随机字符串
        @return: 生成的xml字符串


text_length = len(text)<EOL>amount_to_pad = self.block_size - (text_length % self.block_size)<EOL>if amount_to_pad == <NUM_LIT:0>:<EOL><INDENT>amount_to_pad = self.block_size<EOL><DEDENT>pad = chr(amount_to_pad)<EOL>return text + pad * amount_to_pad<EOL>

对需要加密的明文进行填充补位
        @param text: 需要进行填充补位操作的明文
        @return: 补齐明文字符串


pad = ord(decrypted[-<NUM_LIT:1>])<EOL>if pad < <NUM_LIT:1> or pad > <NUM_LIT:32>:<EOL><INDENT>pad = <NUM_LIT:0><EOL><DEDENT>return decrypted[:-pad]<EOL>

删除解密后明文的补位字符
        @param decrypted: 解密后的明文
        @return: 删除补位字符后的明文


<EOL>text = self.get_random_str() + struct.pack(<EOL>"<STR_LIT:I>", socket.htonl(len(text))) + text + appid<EOL>pkcs7 = PKCS7Encoder()<EOL>text = pkcs7.encode(text)<EOL>cryptor = AES.new(self.key, self.mode, self.key[:<NUM_LIT:16>])<EOL>try:<EOL><INDENT>ciphertext = cryptor.encrypt(text)<EOL>return WXBizMsgCrypt_OK, base64.b64encode(ciphertext)<EOL><DEDENT>except Exception:<EOL><INDENT>return WXBizMsgCrypt_EncryptAES_Error, None<EOL><DEDENT>

对明文进行加密
        @param text: 需要加密的明文
        @return: 加密得到的字符串


try:<EOL><INDENT>cryptor = AES.new(self.key, self.mode, self.key[:<NUM_LIT:16>])<EOL>plain_text = cryptor.decrypt(base64.b64decode(text))<EOL><DEDENT>except Exception:<EOL><INDENT>return WXBizMsgCrypt_DecryptAES_Error, None<EOL><DEDENT>try:<EOL><INDENT>pad = ord(plain_text[-<NUM_LIT:1>])<EOL>content = plain_text[<NUM_LIT:16>:-pad]<EOL>xml_len = socket.ntohl(struct.unpack("<STR_LIT:I>", content[:<NUM_LIT:4>])[<NUM_LIT:0>])<EOL>xml_content = content[<NUM_LIT:4>:xml_len+<NUM_LIT:4>]<EOL>from_appid = content[xml_len+<NUM_LIT:4>:]<EOL><DEDENT>except Exception:<EOL><INDENT>return WXBizMsgCrypt_IllegalBuffer, None<EOL><DEDENT>if from_appid != appid:<EOL><INDENT>return WXBizMsgCrypt_ValidateAppidOrCorpid_Error, None<EOL><DEDENT>return <NUM_LIT:0>, xml_content<EOL>

对解密后的明文进行补位删除
        @param text: 密文
        @return: 删除填充补位后的明文


rule = string.letters + string.digits<EOL>str = random.sample(rule, <NUM_LIT:16>)<EOL>return "<STR_LIT>".join(str)<EOL>

随机生成16位字符串
        @return: 16位字符串


under = target_len - len(unpadded)<EOL>if under <= <NUM_LIT:0>:<EOL><INDENT>return unpadded<EOL><DEDENT>return unpadded + ('<STR_LIT:U+0020>' * under)<EOL>

Pad a string to the target length in characters, or return the original
string if it's longer than the target length.


longest_row_len = max([len(row) for row in table])<EOL>for row in table:<EOL><INDENT>while len(row) < longest_row_len:<EOL><INDENT>row.append('<STR_LIT>')<EOL><DEDENT><DEDENT>return table<EOL>

Pad short rows to the length of the longest row to help render "jagged"
CSV files


col_sizes = [max(map(len, col)) for col in zip(*table)]<EOL>for row in table:<EOL><INDENT>for cell_num, cell in enumerate(row):<EOL><INDENT>row[cell_num] = pad_to(cell, col_sizes[cell_num])<EOL><DEDENT><DEDENT>return table<EOL>

Pad each cell to the size of the largest cell in its column.


def horiz_div(col_widths, horiz, vert, padding):

horizs = [horiz * w for w in col_widths]<EOL>div = '<STR_LIT>'.join([padding * horiz, vert, padding * horiz])<EOL>return div.join(horizs)<EOL>

Create the column dividers for a table with given column widths.

col_widths: list of column widths
horiz: the character to use for a horizontal divider
vert: the character to use for a vertical divider
padding: amount of padding to add to each side of a column


def add_dividers(row, divider, padding):

div = '<STR_LIT>'.join([padding * '<STR_LIT:U+0020>', divider, padding * '<STR_LIT:U+0020>'])<EOL>return div.join(row)<EOL>

Add dividers and padding to a row of cells and return a string.


def md_table(table, *, padding=DEFAULT_PADDING, divider='<STR_LIT:|>', header_div='<STR_LIT:->'):

table = normalize_cols(table)<EOL>table = pad_cells(table)<EOL>header = table[<NUM_LIT:0>]<EOL>body = table[<NUM_LIT:1>:]<EOL>col_widths = [len(cell) for cell in header]<EOL>horiz = horiz_div(col_widths, header_div, divider, padding)<EOL>header = add_dividers(header, divider, padding)<EOL>body = [add_dividers(row, divider, padding) for row in body]<EOL>table = [header, horiz]<EOL>table.extend(body)<EOL>table = [row.rstrip() for row in table]<EOL>return '<STR_LIT:\n>'.join(table)<EOL>

Convert a 2D array of items into a Markdown table.

padding: the number of padding spaces on either side of each divider
divider: the vertical divider to place between columns
header_div: the horizontal divider to place between the header row and
    body cells


self.vis.delete()<EOL>v = self.vis["<STR_LIT>"]<EOL>filename = os.path.join(meshcat.viewer_assets_path(),<EOL>"<STR_LIT>")<EOL>with open(filename, "<STR_LIT:r>") as f:<EOL><INDENT>fio = StringIO(f.read())<EOL>v["<STR_LIT>"].set_object(g.Mesh(g.ObjMeshGeometry.from_stream(fio)))<EOL>v["<STR_LIT>"].set_transform(tf.translation_matrix([<NUM_LIT:0>, <NUM_LIT:0.0>, <NUM_LIT:0>]))<EOL><DEDENT>filename = os.path.join(meshcat.viewer_assets_path(),<EOL>"<STR_LIT>")<EOL>with open(filename, "<STR_LIT:r>") as f:<EOL><INDENT>fio = StringIO(f.read())<EOL>v["<STR_LIT>"].set_object(g.Mesh(g.StlMeshGeometry.from_stream(fio)))<EOL>v["<STR_LIT>"].set_transform(tf.translation_matrix([<NUM_LIT:0>, -<NUM_LIT:0.5>, <NUM_LIT:0>]))<EOL><DEDENT>filename = os.path.join(meshcat.viewer_assets_path(),<EOL>"<STR_LIT>")<EOL>with open(filename, "<STR_LIT:rb>") as f:<EOL><INDENT>fio = BytesIO(f.read())<EOL>v["<STR_LIT>"].set_object(g.Mesh(g.StlMeshGeometry.from_stream(fio)))<EOL>v["<STR_LIT>"].set_transform(tf.translation_matrix([<NUM_LIT:0>, -<NUM_LIT:1.0>, <NUM_LIT:0>]))<EOL><DEDENT>filename = os.path.join(meshcat.viewer_assets_path(),<EOL>"<STR_LIT>")<EOL>with open(filename, "<STR_LIT:r>") as f:<EOL><INDENT>fio = StringIO(f.read())<EOL>v["<STR_LIT>"].set_object(g.Mesh(g.DaeMeshGeometry.from_stream(fio)))<EOL>v["<STR_LIT>"].set_transform(tf.translation_matrix([<NUM_LIT:0>, -<NUM_LIT>, <NUM_LIT:0>]))<EOL><DEDENT>

Applications using meshcat may already have meshes loaded in memory. It is
        more efficient to load these meshes with streams rather than going to and then
        from a file on disk. To test this we are importing meshes from disk and
        converting them into streams so it kind of defeats the intended purpose! But at
        least it tests the functionality.


def convert_frames_to_video(tar_file_path, output_path="<STR_LIT>", framerate=<NUM_LIT>, overwrite=False):

output_path = os.path.abspath(output_path)<EOL>if os.path.isfile(output_path) and not overwrite:<EOL><INDENT>raise ValueError("<STR_LIT>".format(output_path))<EOL><DEDENT>with tempfile.TemporaryDirectory() as tmp_dir:<EOL><INDENT>with tarfile.open(tar_file_path) as tar:<EOL><INDENT>tar.extractall(tmp_dir)<EOL><DEDENT>args = ["<STR_LIT>",<EOL>"<STR_LIT>", str(framerate),<EOL>"<STR_LIT>", r"<STR_LIT>",<EOL>"<STR_LIT>", "<STR_LIT>",<EOL>"<STR_LIT>", "<STR_LIT>",<EOL>"<STR_LIT>", "<STR_LIT>"]<EOL>if overwrite:<EOL><INDENT>args.append("<STR_LIT>")<EOL><DEDENT>args.append(output_path)<EOL>try:<EOL><INDENT>subprocess.check_call(args, cwd=tmp_dir)<EOL><DEDENT>except subprocess.CalledProcessError as e:<EOL><INDENT>print("""<STR_LIT>""")<EOL>raise<EOL><DEDENT><DEDENT>print("<STR_LIT>".format(output_path))<EOL>return output_path<EOL>

Try to convert a tar file containing a sequence of frames saved by the
meshcat viewer into a single video file.

This relies on having `ffmpeg` installed on your system.


return numpy.identity(<NUM_LIT:4>)<EOL>

Return 4x4 identity/unit matrix.

    >>> I = identity_matrix()
    >>> numpy.allclose(I, numpy.dot(I, I))
    True
    >>> numpy.sum(I), numpy.trace(I)
    (4.0, 4.0)
    >>> numpy.allclose(I, numpy.identity(4))
    True


M = numpy.identity(<NUM_LIT:4>)<EOL>M[:<NUM_LIT:3>, <NUM_LIT:3>] = direction[:<NUM_LIT:3>]<EOL>return M<EOL>

Return matrix to translate by direction vector.

    >>> v = numpy.random.random(3) - 0.5
    >>> numpy.allclose(v, translation_matrix(v)[:3, 3])
    True


return numpy.array(matrix, copy=False)[:<NUM_LIT:3>, <NUM_LIT:3>].copy()<EOL>

Return translation vector from translation matrix.

    >>> v0 = numpy.random.random(3) - 0.5
    >>> v1 = translation_from_matrix(translation_matrix(v0))
    >>> numpy.allclose(v0, v1)
    True


normal = unit_vector(normal[:<NUM_LIT:3>])<EOL>M = numpy.identity(<NUM_LIT:4>)<EOL>M[:<NUM_LIT:3>, :<NUM_LIT:3>] -= <NUM_LIT> * numpy.outer(normal, normal)<EOL>M[:<NUM_LIT:3>, <NUM_LIT:3>] = (<NUM_LIT> * numpy.dot(point[:<NUM_LIT:3>], normal)) * normal<EOL>return M<EOL>

Return matrix to mirror at plane defined by point and normal vector.

    >>> v0 = numpy.random.random(4) - 0.5
    >>> v0[3] = 1.
    >>> v1 = numpy.random.random(3) - 0.5
    >>> R = reflection_matrix(v0, v1)
    >>> numpy.allclose(2, numpy.trace(R))
    True
    >>> numpy.allclose(v0, numpy.dot(R, v0))
    True
    >>> v2 = v0.copy()
    >>> v2[:3] += v1
    >>> v3 = v0.copy()
    >>> v2[:3] -= v1
    >>> numpy.allclose(v2, numpy.dot(R, v3))
    True


M = numpy.array(matrix, dtype=numpy.float64, copy=False)<EOL>w, V = numpy.linalg.eig(M[:<NUM_LIT:3>, :<NUM_LIT:3>])<EOL>i = numpy.where(abs(numpy.real(w) + <NUM_LIT:1.0>) < <NUM_LIT>)[<NUM_LIT:0>]<EOL>if not len(i):<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>normal = numpy.real(V[:, i[<NUM_LIT:0>]]).squeeze()<EOL>w, V = numpy.linalg.eig(M)<EOL>i = numpy.where(abs(numpy.real(w) - <NUM_LIT:1.0>) < <NUM_LIT>)[<NUM_LIT:0>]<EOL>if not len(i):<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>point = numpy.real(V[:, i[-<NUM_LIT:1>]]).squeeze()<EOL>point /= point[<NUM_LIT:3>]<EOL>return point, normal<EOL>

Return mirror plane point and normal vector from reflection matrix.

    >>> v0 = numpy.random.random(3) - 0.5
    >>> v1 = numpy.random.random(3) - 0.5
    >>> M0 = reflection_matrix(v0, v1)
    >>> point, normal = reflection_from_matrix(M0)
    >>> M1 = reflection_matrix(point, normal)
    >>> is_same_transform(M0, M1)
    True


def rotation_matrix(angle, direction, point=None):

sina = math.sin(angle)<EOL>cosa = math.cos(angle)<EOL>direction = unit_vector(direction[:<NUM_LIT:3>])<EOL>R = numpy.diag([cosa, cosa, cosa])<EOL>R += numpy.outer(direction, direction) * (<NUM_LIT:1.0> - cosa)<EOL>direction *= sina<EOL>R += numpy.array([[ <NUM_LIT:0.0>,         -direction[<NUM_LIT:2>],  direction[<NUM_LIT:1>]],<EOL>[ direction[<NUM_LIT:2>], <NUM_LIT:0.0>,          -direction[<NUM_LIT:0>]],<EOL>[-direction[<NUM_LIT:1>], direction[<NUM_LIT:0>],  <NUM_LIT:0.0>]])<EOL>M = numpy.identity(<NUM_LIT:4>)<EOL>M[:<NUM_LIT:3>, :<NUM_LIT:3>] = R<EOL>if point is not None:<EOL><INDENT>point = numpy.array(point[:<NUM_LIT:3>], dtype=numpy.float64, copy=False)<EOL>M[:<NUM_LIT:3>, <NUM_LIT:3>] = point - numpy.dot(R, point)<EOL><DEDENT>return M<EOL>

Return matrix to rotate about axis defined by point and direction.

    >>> R = rotation_matrix(math.pi/2, [0, 0, 1], [1, 0, 0])
    >>> numpy.allclose(numpy.dot(R, [0, 0, 0, 1]), [1, -1, 0, 1])
    True
    >>> angle = (random.random() - 0.5) * (2*math.pi)
    >>> direc = numpy.random.random(3) - 0.5
    >>> point = numpy.random.random(3) - 0.5
    >>> R0 = rotation_matrix(angle, direc, point)
    >>> R1 = rotation_matrix(angle-2*math.pi, direc, point)
    >>> is_same_transform(R0, R1)
    True
    >>> R0 = rotation_matrix(angle, direc, point)
    >>> R1 = rotation_matrix(-angle, -direc, point)
    >>> is_same_transform(R0, R1)
    True
    >>> I = numpy.identity(4, numpy.float64)
    >>> numpy.allclose(I, rotation_matrix(math.pi*2, direc))
    True
    >>> numpy.allclose(2, numpy.trace(rotation_matrix(math.pi/2,
    ...                                               direc, point)))
    True


R = numpy.array(matrix, dtype=numpy.float64, copy=False)<EOL>R33 = R[:<NUM_LIT:3>, :<NUM_LIT:3>]<EOL>w, W = numpy.linalg.eig(R33.T)<EOL>i = numpy.where(abs(numpy.real(w) - <NUM_LIT:1.0>) < <NUM_LIT>)[<NUM_LIT:0>]<EOL>if not len(i):<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>direction = numpy.real(W[:, i[-<NUM_LIT:1>]]).squeeze()<EOL>w, Q = numpy.linalg.eig(R)<EOL>i = numpy.where(abs(numpy.real(w) - <NUM_LIT:1.0>) < <NUM_LIT>)[<NUM_LIT:0>]<EOL>if not len(i):<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>point = numpy.real(Q[:, i[-<NUM_LIT:1>]]).squeeze()<EOL>point /= point[<NUM_LIT:3>]<EOL>cosa = (numpy.trace(R33) - <NUM_LIT:1.0>) / <NUM_LIT><EOL>if abs(direction[<NUM_LIT:2>]) > <NUM_LIT>:<EOL><INDENT>sina = (R[<NUM_LIT:1>, <NUM_LIT:0>] + (cosa-<NUM_LIT:1.0>)*direction[<NUM_LIT:0>]*direction[<NUM_LIT:1>]) / direction[<NUM_LIT:2>]<EOL><DEDENT>elif abs(direction[<NUM_LIT:1>]) > <NUM_LIT>:<EOL><INDENT>sina = (R[<NUM_LIT:0>, <NUM_LIT:2>] + (cosa-<NUM_LIT:1.0>)*direction[<NUM_LIT:0>]*direction[<NUM_LIT:2>]) / direction[<NUM_LIT:1>]<EOL><DEDENT>else:<EOL><INDENT>sina = (R[<NUM_LIT:2>, <NUM_LIT:1>] + (cosa-<NUM_LIT:1.0>)*direction[<NUM_LIT:1>]*direction[<NUM_LIT:2>]) / direction[<NUM_LIT:0>]<EOL><DEDENT>angle = math.atan2(sina, cosa)<EOL>return angle, direction, point<EOL>

Return rotation angle and axis from rotation matrix.

    >>> angle = (random.random() - 0.5) * (2*math.pi)
    >>> direc = numpy.random.random(3) - 0.5
    >>> point = numpy.random.random(3) - 0.5
    >>> R0 = rotation_matrix(angle, direc, point)
    >>> angle, direc, point = rotation_from_matrix(R0)
    >>> R1 = rotation_matrix(angle, direc, point)
    >>> is_same_transform(R0, R1)
    True


def scale_matrix(factor, origin=None, direction=None):

if direction is None:<EOL><INDENT>M = numpy.diag([factor, factor, factor, <NUM_LIT:1.0>])<EOL>if origin is not None:<EOL><INDENT>M[:<NUM_LIT:3>, <NUM_LIT:3>] = origin[:<NUM_LIT:3>]<EOL>M[:<NUM_LIT:3>, <NUM_LIT:3>] *= <NUM_LIT:1.0> - factor<EOL><DEDENT><DEDENT>else:<EOL><INDENT>direction = unit_vector(direction[:<NUM_LIT:3>])<EOL>factor = <NUM_LIT:1.0> - factor<EOL>M = numpy.identity(<NUM_LIT:4>)<EOL>M[:<NUM_LIT:3>, :<NUM_LIT:3>] -= factor * numpy.outer(direction, direction)<EOL>if origin is not None:<EOL><INDENT>M[:<NUM_LIT:3>, <NUM_LIT:3>] = (factor * numpy.dot(origin[:<NUM_LIT:3>], direction)) * direction<EOL><DEDENT><DEDENT>return M<EOL>

Return matrix to scale by factor around origin in direction.

    Use factor -1 for point symmetry.

    >>> v = (numpy.random.rand(4, 5) - 0.5) * 20
    >>> v[3] = 1
    >>> S = scale_matrix(-1.234)
    >>> numpy.allclose(numpy.dot(S, v)[:3], -1.234*v[:3])
    True
    >>> factor = random.random() * 10 - 5
    >>> origin = numpy.random.random(3) - 0.5
    >>> direct = numpy.random.random(3) - 0.5
    >>> S = scale_matrix(factor, origin)
    >>> S = scale_matrix(factor, origin, direct)


M = numpy.array(matrix, dtype=numpy.float64, copy=False)<EOL>M33 = M[:<NUM_LIT:3>, :<NUM_LIT:3>]<EOL>factor = numpy.trace(M33) - <NUM_LIT><EOL>try:<EOL><INDENT>w, V = numpy.linalg.eig(M33)<EOL>i = numpy.where(abs(numpy.real(w) - factor) < <NUM_LIT>)[<NUM_LIT:0>][<NUM_LIT:0>]<EOL>direction = numpy.real(V[:, i]).squeeze()<EOL>direction /= vector_norm(direction)<EOL><DEDENT>except IndexError:<EOL><INDENT>factor = (factor + <NUM_LIT>) / <NUM_LIT><EOL>direction = None<EOL><DEDENT>w, V = numpy.linalg.eig(M)<EOL>i = numpy.where(abs(numpy.real(w) - <NUM_LIT:1.0>) < <NUM_LIT>)[<NUM_LIT:0>]<EOL>if not len(i):<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>origin = numpy.real(V[:, i[-<NUM_LIT:1>]]).squeeze()<EOL>origin /= origin[<NUM_LIT:3>]<EOL>return factor, origin, direction<EOL>

Return scaling factor, origin and direction from scaling matrix.

    >>> factor = random.random() * 10 - 5
    >>> origin = numpy.random.random(3) - 0.5
    >>> direct = numpy.random.random(3) - 0.5
    >>> S0 = scale_matrix(factor, origin)
    >>> factor, origin, direction = scale_from_matrix(S0)
    >>> S1 = scale_matrix(factor, origin, direction)
    >>> is_same_transform(S0, S1)
    True
    >>> S0 = scale_matrix(factor, origin, direct)
    >>> factor, origin, direction = scale_from_matrix(S0)
    >>> S1 = scale_matrix(factor, origin, direction)
    >>> is_same_transform(S0, S1)
    True


def projection_matrix(point, normal, direction=None,<EOL>perspective=None, pseudo=False):

M = numpy.identity(<NUM_LIT:4>)<EOL>point = numpy.array(point[:<NUM_LIT:3>], dtype=numpy.float64, copy=False)<EOL>normal = unit_vector(normal[:<NUM_LIT:3>])<EOL>if perspective is not None:<EOL><INDENT>perspective = numpy.array(perspective[:<NUM_LIT:3>], dtype=numpy.float64,<EOL>copy=False)<EOL>M[<NUM_LIT:0>, <NUM_LIT:0>] = M[<NUM_LIT:1>, <NUM_LIT:1>] = M[<NUM_LIT:2>, <NUM_LIT:2>] = numpy.dot(perspective-point, normal)<EOL>M[:<NUM_LIT:3>, :<NUM_LIT:3>] -= numpy.outer(perspective, normal)<EOL>if pseudo:<EOL><INDENT>M[:<NUM_LIT:3>, :<NUM_LIT:3>] -= numpy.outer(normal, normal)<EOL>M[:<NUM_LIT:3>, <NUM_LIT:3>] = numpy.dot(point, normal) * (perspective+normal)<EOL><DEDENT>else:<EOL><INDENT>M[:<NUM_LIT:3>, <NUM_LIT:3>] = numpy.dot(point, normal) * perspective<EOL><DEDENT>M[<NUM_LIT:3>, :<NUM_LIT:3>] = -normal<EOL>M[<NUM_LIT:3>, <NUM_LIT:3>] = numpy.dot(perspective, normal)<EOL><DEDENT>elif direction is not None:<EOL><INDENT>direction = numpy.array(direction[:<NUM_LIT:3>], dtype=numpy.float64, copy=False)<EOL>scale = numpy.dot(direction, normal)<EOL>M[:<NUM_LIT:3>, :<NUM_LIT:3>] -= numpy.outer(direction, normal) / scale<EOL>M[:<NUM_LIT:3>, <NUM_LIT:3>] = direction * (numpy.dot(point, normal) / scale)<EOL><DEDENT>else:<EOL><INDENT>M[:<NUM_LIT:3>, :<NUM_LIT:3>] -= numpy.outer(normal, normal)<EOL>M[:<NUM_LIT:3>, <NUM_LIT:3>] = numpy.dot(point, normal) * normal<EOL><DEDENT>return M<EOL>

Return matrix to project onto plane defined by point and normal.

    Using either perspective point, projection direction, or none of both.

    If pseudo is True, perspective projections will preserve relative depth
    such that Perspective = dot(Orthogonal, PseudoPerspective).

    >>> P = projection_matrix([0, 0, 0], [1, 0, 0])
    >>> numpy.allclose(P[1:, 1:], numpy.identity(4)[1:, 1:])
    True
    >>> point = numpy.random.random(3) - 0.5
    >>> normal = numpy.random.random(3) - 0.5
    >>> direct = numpy.random.random(3) - 0.5
    >>> persp = numpy.random.random(3) - 0.5
    >>> P0 = projection_matrix(point, normal)
    >>> P1 = projection_matrix(point, normal, direction=direct)
    >>> P2 = projection_matrix(point, normal, perspective=persp)
    >>> P3 = projection_matrix(point, normal, perspective=persp, pseudo=True)
    >>> is_same_transform(P2, numpy.dot(P0, P3))
    True
    >>> P = projection_matrix([3, 0, 0], [1, 1, 0], [1, 0, 0])
    >>> v0 = (numpy.random.rand(4, 5) - 0.5) * 20
    >>> v0[3] = 1
    >>> v1 = numpy.dot(P, v0)
    >>> numpy.allclose(v1[1], v0[1])
    True
    >>> numpy.allclose(v1[0], 3-v1[1])
    True


M = numpy.array(matrix, dtype=numpy.float64, copy=False)<EOL>M33 = M[:<NUM_LIT:3>, :<NUM_LIT:3>]<EOL>w, V = numpy.linalg.eig(M)<EOL>i = numpy.where(abs(numpy.real(w) - <NUM_LIT:1.0>) < <NUM_LIT>)[<NUM_LIT:0>]<EOL>if not pseudo and len(i):<EOL><INDENT>point = numpy.real(V[:, i[-<NUM_LIT:1>]]).squeeze()<EOL>point /= point[<NUM_LIT:3>]<EOL>w, V = numpy.linalg.eig(M33)<EOL>i = numpy.where(abs(numpy.real(w)) < <NUM_LIT>)[<NUM_LIT:0>]<EOL>if not len(i):<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>direction = numpy.real(V[:, i[<NUM_LIT:0>]]).squeeze()<EOL>direction /= vector_norm(direction)<EOL>w, V = numpy.linalg.eig(M33.T)<EOL>i = numpy.where(abs(numpy.real(w)) < <NUM_LIT>)[<NUM_LIT:0>]<EOL>if len(i):<EOL><INDENT>normal = numpy.real(V[:, i[<NUM_LIT:0>]]).squeeze()<EOL>normal /= vector_norm(normal)<EOL>return point, normal, direction, None, False<EOL><DEDENT>else:<EOL><INDENT>return point, direction, None, None, False<EOL><DEDENT><DEDENT>else:<EOL><INDENT>i = numpy.where(abs(numpy.real(w)) > <NUM_LIT>)[<NUM_LIT:0>]<EOL>if not len(i):<EOL><INDENT>raise ValueError(<EOL>"<STR_LIT>")<EOL><DEDENT>point = numpy.real(V[:, i[-<NUM_LIT:1>]]).squeeze()<EOL>point /= point[<NUM_LIT:3>]<EOL>normal = - M[<NUM_LIT:3>, :<NUM_LIT:3>]<EOL>perspective = M[:<NUM_LIT:3>, <NUM_LIT:3>] / numpy.dot(point[:<NUM_LIT:3>], normal)<EOL>if pseudo:<EOL><INDENT>perspective -= normal<EOL><DEDENT>return point, normal, None, perspective, pseudo<EOL><DEDENT>

Return projection plane and perspective point from projection matrix.

    Return values are same as arguments for projection_matrix function:
    point, normal, direction, perspective, and pseudo.

    >>> point = numpy.random.random(3) - 0.5
    >>> normal = numpy.random.random(3) - 0.5
    >>> direct = numpy.random.random(3) - 0.5
    >>> persp = numpy.random.random(3) - 0.5
    >>> P0 = projection_matrix(point, normal)
    >>> result = projection_from_matrix(P0)
    >>> P1 = projection_matrix(*result)
    >>> is_same_transform(P0, P1)
    True
    >>> P0 = projection_matrix(point, normal, direct)
    >>> result = projection_from_matrix(P0)
    >>> P1 = projection_matrix(*result)
    >>> is_same_transform(P0, P1)
    True
    >>> P0 = projection_matrix(point, normal, perspective=persp, pseudo=False)
    >>> result = projection_from_matrix(P0, pseudo=False)
    >>> P1 = projection_matrix(*result)
    >>> is_same_transform(P0, P1)
    True
    >>> P0 = projection_matrix(point, normal, perspective=persp, pseudo=True)
    >>> result = projection_from_matrix(P0, pseudo=True)
    >>> P1 = projection_matrix(*result)
    >>> is_same_transform(P0, P1)
    True


def clip_matrix(left, right, bottom, top, near, far, perspective=False):

if left >= right or bottom >= top or near >= far:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>if perspective:<EOL><INDENT>if near <= _EPS:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>t = <NUM_LIT> * near<EOL>M = [[t/(left-right), <NUM_LIT:0.0>, (right+left)/(right-left), <NUM_LIT:0.0>],<EOL>[<NUM_LIT:0.0>, t/(bottom-top), (top+bottom)/(top-bottom), <NUM_LIT:0.0>],<EOL>[<NUM_LIT:0.0>, <NUM_LIT:0.0>, (far+near)/(near-far), t*far/(far-near)],<EOL>[<NUM_LIT:0.0>, <NUM_LIT:0.0>, -<NUM_LIT:1.0>, <NUM_LIT:0.0>]]<EOL><DEDENT>else:<EOL><INDENT>M = [[<NUM_LIT>/(right-left), <NUM_LIT:0.0>, <NUM_LIT:0.0>, (right+left)/(left-right)],<EOL>[<NUM_LIT:0.0>, <NUM_LIT>/(top-bottom), <NUM_LIT:0.0>, (top+bottom)/(bottom-top)],<EOL>[<NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT>/(far-near), (far+near)/(near-far)],<EOL>[<NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:1.0>]]<EOL><DEDENT>return numpy.array(M)<EOL>

Return matrix to obtain normalized device coordinates from frustum.

    The frustum bounds are axis-aligned along x (left, right),
    y (bottom, top) and z (near, far).

    Normalized device coordinates are in range [-1, 1] if coordinates are
    inside the frustum.

    If perspective is True the frustum is a truncated pyramid with the
    perspective point at origin and direction along z axis, otherwise an
    orthographic canonical view volume (a box).

    Homogeneous coordinates transformed by the perspective clip matrix
    need to be dehomogenized (divided by w coordinate).

    >>> frustum = numpy.random.rand(6)
    >>> frustum[1] += frustum[0]
    >>> frustum[3] += frustum[2]
    >>> frustum[5] += frustum[4]
    >>> M = clip_matrix(perspective=False, *frustum)
    >>> numpy.dot(M, [frustum[0], frustum[2], frustum[4], 1])
    array([-1., -1., -1.,  1.])
    >>> numpy.dot(M, [frustum[1], frustum[3], frustum[5], 1])
    array([ 1.,  1.,  1.,  1.])
    >>> M = clip_matrix(perspective=True, *frustum)
    >>> v = numpy.dot(M, [frustum[0], frustum[2], frustum[4], 1])
    >>> v / v[3]
    array([-1., -1., -1.,  1.])
    >>> v = numpy.dot(M, [frustum[1], frustum[3], frustum[4], 1])
    >>> v / v[3]
    array([ 1.,  1., -1.,  1.])


def shear_matrix(angle, direction, point, normal):

normal = unit_vector(normal[:<NUM_LIT:3>])<EOL>direction = unit_vector(direction[:<NUM_LIT:3>])<EOL>if abs(numpy.dot(normal, direction)) > <NUM_LIT>:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>angle = math.tan(angle)<EOL>M = numpy.identity(<NUM_LIT:4>)<EOL>M[:<NUM_LIT:3>, :<NUM_LIT:3>] += angle * numpy.outer(direction, normal)<EOL>M[:<NUM_LIT:3>, <NUM_LIT:3>] = -angle * numpy.dot(point[:<NUM_LIT:3>], normal) * direction<EOL>return M<EOL>

Return matrix to shear by angle along direction vector on shear plane.

    The shear plane is defined by a point and normal vector. The direction
    vector must be orthogonal to the plane's normal vector.

    A point P is transformed by the shear matrix into P" such that
    the vector P-P" is parallel to the direction vector and its extent is
    given by the angle of P-P'-P", where P' is the orthogonal projection
    of P onto the shear plane.

    >>> angle = (random.random() - 0.5) * 4*math.pi
    >>> direct = numpy.random.random(3) - 0.5
    >>> point = numpy.random.random(3) - 0.5
    >>> normal = numpy.cross(direct, numpy.random.random(3))
    >>> S = shear_matrix(angle, direct, point, normal)
    >>> numpy.allclose(1, numpy.linalg.det(S))
    True


M = numpy.array(matrix, dtype=numpy.float64, copy=False)<EOL>M33 = M[:<NUM_LIT:3>, :<NUM_LIT:3>]<EOL>w, V = numpy.linalg.eig(M33)<EOL>i = numpy.where(abs(numpy.real(w) - <NUM_LIT:1.0>) < <NUM_LIT>)[<NUM_LIT:0>]<EOL>if len(i) < <NUM_LIT:2>:<EOL><INDENT>raise ValueError("<STR_LIT>" % w)<EOL><DEDENT>V = numpy.real(V[:, i]).squeeze().T<EOL>lenorm = -<NUM_LIT:1.0><EOL>for i0, i1 in ((<NUM_LIT:0>, <NUM_LIT:1>), (<NUM_LIT:0>, <NUM_LIT:2>), (<NUM_LIT:1>, <NUM_LIT:2>)):<EOL><INDENT>n = numpy.cross(V[i0], V[i1])<EOL>w = vector_norm(n)<EOL>if w > lenorm:<EOL><INDENT>lenorm = w<EOL>normal = n<EOL><DEDENT><DEDENT>normal /= lenorm<EOL>direction = numpy.dot(M33 - numpy.identity(<NUM_LIT:3>), normal)<EOL>angle = vector_norm(direction)<EOL>direction /= angle<EOL>angle = math.atan(angle)<EOL>w, V = numpy.linalg.eig(M)<EOL>i = numpy.where(abs(numpy.real(w) - <NUM_LIT:1.0>) < <NUM_LIT>)[<NUM_LIT:0>]<EOL>if not len(i):<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>point = numpy.real(V[:, i[-<NUM_LIT:1>]]).squeeze()<EOL>point /= point[<NUM_LIT:3>]<EOL>return angle, direction, point, normal<EOL>

Return shear angle, direction and plane from shear matrix.

    >>> angle = (random.random() - 0.5) * 4*math.pi
    >>> direct = numpy.random.random(3) - 0.5
    >>> point = numpy.random.random(3) - 0.5
    >>> normal = numpy.cross(direct, numpy.random.random(3))
    >>> S0 = shear_matrix(angle, direct, point, normal)
    >>> angle, direct, point, normal = shear_from_matrix(S0)
    >>> S1 = shear_matrix(angle, direct, point, normal)
    >>> is_same_transform(S0, S1)
    True


M = numpy.array(matrix, dtype=numpy.float64, copy=True).T<EOL>if abs(M[<NUM_LIT:3>, <NUM_LIT:3>]) < _EPS:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>M /= M[<NUM_LIT:3>, <NUM_LIT:3>]<EOL>P = M.copy()<EOL>P[:, <NUM_LIT:3>] = <NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:1.0><EOL>if not numpy.linalg.det(P):<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>scale = numpy.zeros((<NUM_LIT:3>, ))<EOL>shear = [<NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>]<EOL>angles = [<NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>]<EOL>if any(abs(M[:<NUM_LIT:3>, <NUM_LIT:3>]) > _EPS):<EOL><INDENT>perspective = numpy.dot(M[:, <NUM_LIT:3>], numpy.linalg.inv(P.T))<EOL>M[:, <NUM_LIT:3>] = <NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:1.0><EOL><DEDENT>else:<EOL><INDENT>perspective = numpy.array([<NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:1.0>])<EOL><DEDENT>translate = M[<NUM_LIT:3>, :<NUM_LIT:3>].copy()<EOL>M[<NUM_LIT:3>, :<NUM_LIT:3>] = <NUM_LIT:0.0><EOL>row = M[:<NUM_LIT:3>, :<NUM_LIT:3>].copy()<EOL>scale[<NUM_LIT:0>] = vector_norm(row[<NUM_LIT:0>])<EOL>row[<NUM_LIT:0>] /= scale[<NUM_LIT:0>]<EOL>shear[<NUM_LIT:0>] = numpy.dot(row[<NUM_LIT:0>], row[<NUM_LIT:1>])<EOL>row[<NUM_LIT:1>] -= row[<NUM_LIT:0>] * shear[<NUM_LIT:0>]<EOL>scale[<NUM_LIT:1>] = vector_norm(row[<NUM_LIT:1>])<EOL>row[<NUM_LIT:1>] /= scale[<NUM_LIT:1>]<EOL>shear[<NUM_LIT:0>] /= scale[<NUM_LIT:1>]<EOL>shear[<NUM_LIT:1>] = numpy.dot(row[<NUM_LIT:0>], row[<NUM_LIT:2>])<EOL>row[<NUM_LIT:2>] -= row[<NUM_LIT:0>] * shear[<NUM_LIT:1>]<EOL>shear[<NUM_LIT:2>] = numpy.dot(row[<NUM_LIT:1>], row[<NUM_LIT:2>])<EOL>row[<NUM_LIT:2>] -= row[<NUM_LIT:1>] * shear[<NUM_LIT:2>]<EOL>scale[<NUM_LIT:2>] = vector_norm(row[<NUM_LIT:2>])<EOL>row[<NUM_LIT:2>] /= scale[<NUM_LIT:2>]<EOL>shear[<NUM_LIT:1>:] /= scale[<NUM_LIT:2>]<EOL>if numpy.dot(row[<NUM_LIT:0>], numpy.cross(row[<NUM_LIT:1>], row[<NUM_LIT:2>])) < <NUM_LIT:0>:<EOL><INDENT>numpy.negative(scale, scale)<EOL>numpy.negative(row, row)<EOL><DEDENT>angles[<NUM_LIT:1>] = math.asin(-row[<NUM_LIT:0>, <NUM_LIT:2>])<EOL>if math.cos(angles[<NUM_LIT:1>]):<EOL><INDENT>angles[<NUM_LIT:0>] = math.atan2(row[<NUM_LIT:1>, <NUM_LIT:2>], row[<NUM_LIT:2>, <NUM_LIT:2>])<EOL>angles[<NUM_LIT:2>] = math.atan2(row[<NUM_LIT:0>, <NUM_LIT:1>], row[<NUM_LIT:0>, <NUM_LIT:0>])<EOL><DEDENT>else:<EOL><INDENT>angles[<NUM_LIT:0>] = math.atan2(-row[<NUM_LIT:2>, <NUM_LIT:1>], row[<NUM_LIT:1>, <NUM_LIT:1>])<EOL>angles[<NUM_LIT:2>] = <NUM_LIT:0.0><EOL><DEDENT>return scale, shear, angles, translate, perspective<EOL>

Return sequence of transformations from transformation matrix.

    matrix : array_like
        Non-degenerative homogeneous transformation matrix

    Return tuple of:
        scale : vector of 3 scaling factors
        shear : list of shear factors for x-y, x-z, y-z axes
        angles : list of Euler angles about static x, y, z axes
        translate : translation vector along x, y, z axes
        perspective : perspective partition of matrix

    Raise ValueError if matrix is of wrong type or degenerative.

    >>> T0 = translation_matrix([1, 2, 3])
    >>> scale, shear, angles, trans, persp = decompose_matrix(T0)
    >>> T1 = translation_matrix(trans)
    >>> numpy.allclose(T0, T1)
    True
    >>> S = scale_matrix(0.123)
    >>> scale, shear, angles, trans, persp = decompose_matrix(S)
    >>> scale[0]
    0.123
    >>> R0 = euler_matrix(1, 2, 3)
    >>> scale, shear, angles, trans, persp = decompose_matrix(R0)
    >>> R1 = euler_matrix(*angles)
    >>> numpy.allclose(R0, R1)
    True


def compose_matrix(scale=None, shear=None, angles=None, translate=None,<EOL>perspective=None):

M = numpy.identity(<NUM_LIT:4>)<EOL>if perspective is not None:<EOL><INDENT>P = numpy.identity(<NUM_LIT:4>)<EOL>P[<NUM_LIT:3>, :] = perspective[:<NUM_LIT:4>]<EOL>M = numpy.dot(M, P)<EOL><DEDENT>if translate is not None:<EOL><INDENT>T = numpy.identity(<NUM_LIT:4>)<EOL>T[:<NUM_LIT:3>, <NUM_LIT:3>] = translate[:<NUM_LIT:3>]<EOL>M = numpy.dot(M, T)<EOL><DEDENT>if angles is not None:<EOL><INDENT>R = euler_matrix(angles[<NUM_LIT:0>], angles[<NUM_LIT:1>], angles[<NUM_LIT:2>], '<STR_LIT>')<EOL>M = numpy.dot(M, R)<EOL><DEDENT>if shear is not None:<EOL><INDENT>Z = numpy.identity(<NUM_LIT:4>)<EOL>Z[<NUM_LIT:1>, <NUM_LIT:2>] = shear[<NUM_LIT:2>]<EOL>Z[<NUM_LIT:0>, <NUM_LIT:2>] = shear[<NUM_LIT:1>]<EOL>Z[<NUM_LIT:0>, <NUM_LIT:1>] = shear[<NUM_LIT:0>]<EOL>M = numpy.dot(M, Z)<EOL><DEDENT>if scale is not None:<EOL><INDENT>S = numpy.identity(<NUM_LIT:4>)<EOL>S[<NUM_LIT:0>, <NUM_LIT:0>] = scale[<NUM_LIT:0>]<EOL>S[<NUM_LIT:1>, <NUM_LIT:1>] = scale[<NUM_LIT:1>]<EOL>S[<NUM_LIT:2>, <NUM_LIT:2>] = scale[<NUM_LIT:2>]<EOL>M = numpy.dot(M, S)<EOL><DEDENT>M /= M[<NUM_LIT:3>, <NUM_LIT:3>]<EOL>return M<EOL>

Return transformation matrix from sequence of transformations.

    This is the inverse of the decompose_matrix function.

    Sequence of transformations:
        scale : vector of 3 scaling factors
        shear : list of shear factors for x-y, x-z, y-z axes
        angles : list of Euler angles about static x, y, z axes
        translate : translation vector along x, y, z axes
        perspective : perspective partition of matrix

    >>> scale = numpy.random.random(3) - 0.5
    >>> shear = numpy.random.random(3) - 0.5
    >>> angles = (numpy.random.random(3) - 0.5) * (2*math.pi)
    >>> trans = numpy.random.random(3) - 0.5
    >>> persp = numpy.random.random(4) - 0.5
    >>> M0 = compose_matrix(scale, shear, angles, trans, persp)
    >>> result = decompose_matrix(M0)
    >>> M1 = compose_matrix(*result)
    >>> is_same_transform(M0, M1)
    True


a, b, c = lengths<EOL>angles = numpy.radians(angles)<EOL>sina, sinb, _ = numpy.sin(angles)<EOL>cosa, cosb, cosg = numpy.cos(angles)<EOL>co = (cosa * cosb - cosg) / (sina * sinb)<EOL>return numpy.array([<EOL>[ a*sinb*math.sqrt(<NUM_LIT:1.0>-co*co),  <NUM_LIT:0.0>,    <NUM_LIT:0.0>, <NUM_LIT:0.0>],<EOL>[-a*sinb*co,                    b*sina, <NUM_LIT:0.0>, <NUM_LIT:0.0>],<EOL>[ a*cosb,                       b*cosa, c,   <NUM_LIT:0.0>],<EOL>[ <NUM_LIT:0.0>,                          <NUM_LIT:0.0>,    <NUM_LIT:0.0>, <NUM_LIT:1.0>]])<EOL>

Return orthogonalization matrix for crystallographic cell coordinates.

    Angles are expected in degrees.

    The de-orthogonalization matrix is the inverse.

    >>> O = orthogonalization_matrix([10, 10, 10], [90, 90, 90])
    >>> numpy.allclose(O[:3, :3], numpy.identity(3, float) * 10)
    True
    >>> O = orthogonalization_matrix([9.8, 12.0, 15.5], [87.2, 80.7, 69.7])
    >>> numpy.allclose(numpy.sum(O), 43.063229)
    True


def affine_matrix_from_points(v0, v1, shear=True, scale=True, usesvd=True):

v0 = numpy.array(v0, dtype=numpy.float64, copy=True)<EOL>v1 = numpy.array(v1, dtype=numpy.float64, copy=True)<EOL>ndims = v0.shape[<NUM_LIT:0>]<EOL>if ndims < <NUM_LIT:2> or v0.shape[<NUM_LIT:1>] < ndims or v0.shape != v1.shape:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>t0 = -numpy.mean(v0, axis=<NUM_LIT:1>)<EOL>M0 = numpy.identity(ndims+<NUM_LIT:1>)<EOL>M0[:ndims, ndims] = t0<EOL>v0 += t0.reshape(ndims, <NUM_LIT:1>)<EOL>t1 = -numpy.mean(v1, axis=<NUM_LIT:1>)<EOL>M1 = numpy.identity(ndims+<NUM_LIT:1>)<EOL>M1[:ndims, ndims] = t1<EOL>v1 += t1.reshape(ndims, <NUM_LIT:1>)<EOL>if shear:<EOL><INDENT>A = numpy.concatenate((v0, v1), axis=<NUM_LIT:0>)<EOL>u, s, vh = numpy.linalg.svd(A.T)<EOL>vh = vh[:ndims].T<EOL>B = vh[:ndims]<EOL>C = vh[ndims:<NUM_LIT:2>*ndims]<EOL>t = numpy.dot(C, numpy.linalg.pinv(B))<EOL>t = numpy.concatenate((t, numpy.zeros((ndims, <NUM_LIT:1>))), axis=<NUM_LIT:1>)<EOL>M = numpy.vstack((t, ((<NUM_LIT:0.0>,)*ndims) + (<NUM_LIT:1.0>,)))<EOL><DEDENT>elif usesvd or ndims != <NUM_LIT:3>:<EOL><INDENT>u, s, vh = numpy.linalg.svd(numpy.dot(v1, v0.T))<EOL>R = numpy.dot(u, vh)<EOL>if numpy.linalg.det(R) < <NUM_LIT:0.0>:<EOL><INDENT>R -= numpy.outer(u[:, ndims-<NUM_LIT:1>], vh[ndims-<NUM_LIT:1>, :]*<NUM_LIT>)<EOL>s[-<NUM_LIT:1>] *= -<NUM_LIT:1.0><EOL><DEDENT>M = numpy.identity(ndims+<NUM_LIT:1>)<EOL>M[:ndims, :ndims] = R<EOL><DEDENT>else:<EOL><INDENT>xx, yy, zz = numpy.sum(v0 * v1, axis=<NUM_LIT:1>)<EOL>xy, yz, zx = numpy.sum(v0 * numpy.roll(v1, -<NUM_LIT:1>, axis=<NUM_LIT:0>), axis=<NUM_LIT:1>)<EOL>xz, yx, zy = numpy.sum(v0 * numpy.roll(v1, -<NUM_LIT:2>, axis=<NUM_LIT:0>), axis=<NUM_LIT:1>)<EOL>N = [[xx+yy+zz, <NUM_LIT:0.0>,      <NUM_LIT:0.0>,      <NUM_LIT:0.0>],<EOL>[yz-zy,    xx-yy-zz, <NUM_LIT:0.0>,      <NUM_LIT:0.0>],<EOL>[zx-xz,    xy+yx,    yy-xx-zz, <NUM_LIT:0.0>],<EOL>[xy-yx,    zx+xz,    yz+zy,    zz-xx-yy]]<EOL>w, V = numpy.linalg.eigh(N)<EOL>q = V[:, numpy.argmax(w)]<EOL>q /= vector_norm(q)  <EOL>M = quaternion_matrix(q)<EOL><DEDENT>if scale and not shear:<EOL><INDENT>v0 *= v0<EOL>v1 *= v1<EOL>M[:ndims, :ndims] *= math.sqrt(numpy.sum(v1) / numpy.sum(v0))<EOL><DEDENT>M = numpy.dot(numpy.linalg.inv(M1), numpy.dot(M, M0))<EOL>M /= M[ndims, ndims]<EOL>return M<EOL>

Return affine transform matrix to register two point sets.

    v0 and v1 are shape (ndims, *) arrays of at least ndims non-homogeneous
    coordinates, where ndims is the dimensionality of the coordinate space.

    If shear is False, a similarity transformation matrix is returned.
    If also scale is False, a rigid/Euclidean transformation matrix
    is returned.

    By default the algorithm by Hartley and Zissermann [15] is used.
    If usesvd is True, similarity and Euclidean transformation matrices
    are calculated by minimizing the weighted sum of squared deviations
    (RMSD) according to the algorithm by Kabsch [8].
    Otherwise, and if ndims is 3, the quaternion based algorithm by Horn [9]
    is used, which is slower when using this Python implementation.

    The returned matrix performs rotation, translation and uniform scaling
    (if specified).

    >>> v0 = [[0, 1031, 1031, 0], [0, 0, 1600, 1600]]
    >>> v1 = [[675, 826, 826, 677], [55, 52, 281, 277]]
    >>> affine_matrix_from_points(v0, v1)
    array([[   0.14549,    0.00062,  675.50008],
           [   0.00048,    0.14094,   53.24971],
           [   0.     ,    0.     ,    1.     ]])
    >>> T = translation_matrix(numpy.random.random(3)-0.5)
    >>> R = random_rotation_matrix(numpy.random.random(3))
    >>> S = scale_matrix(random.random())
    >>> M = concatenate_matrices(T, R, S)
    >>> v0 = (numpy.random.rand(4, 100) - 0.5) * 20
    >>> v0[3] = 1
    >>> v1 = numpy.dot(M, v0)
    >>> v0[:3] += numpy.random.normal(0, 1e-8, 300).reshape(3, -1)
    >>> M = affine_matrix_from_points(v0[:3], v1[:3])
    >>> numpy.allclose(v1, numpy.dot(M, v0))
    True

    More examples in superimposition_matrix()


def superimposition_matrix(v0, v1, scale=False, usesvd=True):

v0 = numpy.array(v0, dtype=numpy.float64, copy=False)[:<NUM_LIT:3>]<EOL>v1 = numpy.array(v1, dtype=numpy.float64, copy=False)[:<NUM_LIT:3>]<EOL>return affine_matrix_from_points(v0, v1, shear=False,<EOL>scale=scale, usesvd=usesvd)<EOL>

Return matrix to transform given 3D point set into second point set.

    v0 and v1 are shape (3, *) or (4, *) arrays of at least 3 points.

    The parameters scale and usesvd are explained in the more general
    affine_matrix_from_points function.

    The returned matrix is a similarity or Euclidean transformation matrix.
    This function has a fast C implementation in transformations.c.

    >>> v0 = numpy.random.rand(3, 10)
    >>> M = superimposition_matrix(v0, v0)
    >>> numpy.allclose(M, numpy.identity(4))
    True
    >>> R = random_rotation_matrix(numpy.random.random(3))
    >>> v0 = [[1,0,0], [0,1,0], [0,0,1], [1,1,1]]
    >>> v1 = numpy.dot(R, v0)
    >>> M = superimposition_matrix(v0, v1)
    >>> numpy.allclose(v1, numpy.dot(M, v0))
    True
    >>> v0 = (numpy.random.rand(4, 100) - 0.5) * 20
    >>> v0[3] = 1
    >>> v1 = numpy.dot(R, v0)
    >>> M = superimposition_matrix(v0, v1)
    >>> numpy.allclose(v1, numpy.dot(M, v0))
    True
    >>> S = scale_matrix(random.random())
    >>> T = translation_matrix(numpy.random.random(3)-0.5)
    >>> M = concatenate_matrices(T, R, S)
    >>> v1 = numpy.dot(M, v0)
    >>> v0[:3] += numpy.random.normal(0, 1e-9, 300).reshape(3, -1)
    >>> M = superimposition_matrix(v0, v1, scale=True)
    >>> numpy.allclose(v1, numpy.dot(M, v0))
    True
    >>> M = superimposition_matrix(v0, v1, scale=True, usesvd=False)
    >>> numpy.allclose(v1, numpy.dot(M, v0))
    True
    >>> v = numpy.empty((4, 100, 3))
    >>> v[:, :, 0] = v0
    >>> M = superimposition_matrix(v0, v1, scale=True, usesvd=False)
    >>> numpy.allclose(v1, numpy.dot(M, v[:, :, 0]))
    True


def euler_matrix(ai, aj, ak, axes='<STR_LIT>'):

try:<EOL><INDENT>firstaxis, parity, repetition, frame = _AXES2TUPLE[axes]<EOL><DEDENT>except (AttributeError, KeyError):<EOL><INDENT>_TUPLE2AXES[axes]  <EOL>firstaxis, parity, repetition, frame = axes<EOL><DEDENT>i = firstaxis<EOL>j = _NEXT_AXIS[i+parity]<EOL>k = _NEXT_AXIS[i-parity+<NUM_LIT:1>]<EOL>if frame:<EOL><INDENT>ai, ak = ak, ai<EOL><DEDENT>if parity:<EOL><INDENT>ai, aj, ak = -ai, -aj, -ak<EOL><DEDENT>si, sj, sk = math.sin(ai), math.sin(aj), math.sin(ak)<EOL>ci, cj, ck = math.cos(ai), math.cos(aj), math.cos(ak)<EOL>cc, cs = ci*ck, ci*sk<EOL>sc, ss = si*ck, si*sk<EOL>M = numpy.identity(<NUM_LIT:4>)<EOL>if repetition:<EOL><INDENT>M[i, i] = cj<EOL>M[i, j] = sj*si<EOL>M[i, k] = sj*ci<EOL>M[j, i] = sj*sk<EOL>M[j, j] = -cj*ss+cc<EOL>M[j, k] = -cj*cs-sc<EOL>M[k, i] = -sj*ck<EOL>M[k, j] = cj*sc+cs<EOL>M[k, k] = cj*cc-ss<EOL><DEDENT>else:<EOL><INDENT>M[i, i] = cj*ck<EOL>M[i, j] = sj*sc-cs<EOL>M[i, k] = sj*cc+ss<EOL>M[j, i] = cj*sk<EOL>M[j, j] = sj*ss+cc<EOL>M[j, k] = sj*cs-sc<EOL>M[k, i] = -sj<EOL>M[k, j] = cj*si<EOL>M[k, k] = cj*ci<EOL><DEDENT>return M<EOL>

Return homogeneous rotation matrix from Euler angles and axis sequence.

    ai, aj, ak : Euler's roll, pitch and yaw angles
    axes : One of 24 axis sequences as string or encoded tuple

    >>> R = euler_matrix(1, 2, 3, 'syxz')
    >>> numpy.allclose(numpy.sum(R[0]), -1.34786452)
    True
    >>> R = euler_matrix(1, 2, 3, (0, 1, 0, 1))
    >>> numpy.allclose(numpy.sum(R[0]), -0.383436184)
    True
    >>> ai, aj, ak = (4*math.pi) * (numpy.random.random(3) - 0.5)
    >>> for axes in _AXES2TUPLE.keys():
    ...    R = euler_matrix(ai, aj, ak, axes)
    >>> for axes in _TUPLE2AXES.keys():
    ...    R = euler_matrix(ai, aj, ak, axes)


try:<EOL><INDENT>firstaxis, parity, repetition, frame = _AXES2TUPLE[axes.lower()]<EOL><DEDENT>except (AttributeError, KeyError):<EOL><INDENT>_TUPLE2AXES[axes]  <EOL>firstaxis, parity, repetition, frame = axes<EOL><DEDENT>i = firstaxis<EOL>j = _NEXT_AXIS[i+parity]<EOL>k = _NEXT_AXIS[i-parity+<NUM_LIT:1>]<EOL>M = numpy.array(matrix, dtype=numpy.float64, copy=False)[:<NUM_LIT:3>, :<NUM_LIT:3>]<EOL>if repetition:<EOL><INDENT>sy = math.sqrt(M[i, j]*M[i, j] + M[i, k]*M[i, k])<EOL>if sy > _EPS:<EOL><INDENT>ax = math.atan2( M[i, j],  M[i, k])<EOL>ay = math.atan2( sy,       M[i, i])<EOL>az = math.atan2( M[j, i], -M[k, i])<EOL><DEDENT>else:<EOL><INDENT>ax = math.atan2(-M[j, k],  M[j, j])<EOL>ay = math.atan2( sy,       M[i, i])<EOL>az = <NUM_LIT:0.0><EOL><DEDENT><DEDENT>else:<EOL><INDENT>cy = math.sqrt(M[i, i]*M[i, i] + M[j, i]*M[j, i])<EOL>if cy > _EPS:<EOL><INDENT>ax = math.atan2( M[k, j],  M[k, k])<EOL>ay = math.atan2(-M[k, i],  cy)<EOL>az = math.atan2( M[j, i],  M[i, i])<EOL><DEDENT>else:<EOL><INDENT>ax = math.atan2(-M[j, k],  M[j, j])<EOL>ay = math.atan2(-M[k, i],  cy)<EOL>az = <NUM_LIT:0.0><EOL><DEDENT><DEDENT>if parity:<EOL><INDENT>ax, ay, az = -ax, -ay, -az<EOL><DEDENT>if frame:<EOL><INDENT>ax, az = az, ax<EOL><DEDENT>return ax, ay, az<EOL>

Return Euler angles from rotation matrix for specified axis sequence.

    axes : One of 24 axis sequences as string or encoded tuple

    Note that many Euler angle triplets can describe one matrix.

    >>> R0 = euler_matrix(1, 2, 3, 'syxz')
    >>> al, be, ga = euler_from_matrix(R0, 'syxz')
    >>> R1 = euler_matrix(al, be, ga, 'syxz')
    >>> numpy.allclose(R0, R1)
    True
    >>> angles = (4*math.pi) * (numpy.random.random(3) - 0.5)
    >>> for axes in _AXES2TUPLE.keys():
    ...    R0 = euler_matrix(axes=axes, *angles)
    ...    R1 = euler_matrix(axes=axes, *euler_from_matrix(R0, axes))
    ...    if not numpy.allclose(R0, R1): print(axes, "failed")


return euler_from_matrix(quaternion_matrix(quaternion), axes)<EOL>

Return Euler angles from quaternion for specified axis sequence.

    >>> angles = euler_from_quaternion([0.99810947, 0.06146124, 0, 0])
    >>> numpy.allclose(angles, [0.123, 0, 0])
    True


def quaternion_from_euler(ai, aj, ak, axes='<STR_LIT>'):

try:<EOL><INDENT>firstaxis, parity, repetition, frame = _AXES2TUPLE[axes.lower()]<EOL><DEDENT>except (AttributeError, KeyError):<EOL><INDENT>_TUPLE2AXES[axes]  <EOL>firstaxis, parity, repetition, frame = axes<EOL><DEDENT>i = firstaxis + <NUM_LIT:1><EOL>j = _NEXT_AXIS[i+parity-<NUM_LIT:1>] + <NUM_LIT:1><EOL>k = _NEXT_AXIS[i-parity] + <NUM_LIT:1><EOL>if frame:<EOL><INDENT>ai, ak = ak, ai<EOL><DEDENT>if parity:<EOL><INDENT>aj = -aj<EOL><DEDENT>ai /= <NUM_LIT><EOL>aj /= <NUM_LIT><EOL>ak /= <NUM_LIT><EOL>ci = math.cos(ai)<EOL>si = math.sin(ai)<EOL>cj = math.cos(aj)<EOL>sj = math.sin(aj)<EOL>ck = math.cos(ak)<EOL>sk = math.sin(ak)<EOL>cc = ci*ck<EOL>cs = ci*sk<EOL>sc = si*ck<EOL>ss = si*sk<EOL>q = numpy.empty((<NUM_LIT:4>, ))<EOL>if repetition:<EOL><INDENT>q[<NUM_LIT:0>] = cj*(cc - ss)<EOL>q[i] = cj*(cs + sc)<EOL>q[j] = sj*(cc + ss)<EOL>q[k] = sj*(cs - sc)<EOL><DEDENT>else:<EOL><INDENT>q[<NUM_LIT:0>] = cj*cc + sj*ss<EOL>q[i] = cj*sc - sj*cs<EOL>q[j] = cj*ss + sj*cc<EOL>q[k] = cj*cs - sj*sc<EOL><DEDENT>if parity:<EOL><INDENT>q[j] *= -<NUM_LIT:1.0><EOL><DEDENT>return q<EOL>

Return quaternion from Euler angles and axis sequence.

    ai, aj, ak : Euler's roll, pitch and yaw angles
    axes : One of 24 axis sequences as string or encoded tuple

    >>> q = quaternion_from_euler(1, 2, 3, 'ryxz')
    >>> numpy.allclose(q, [0.435953, 0.310622, -0.718287, 0.444435])
    True


q = numpy.array([<NUM_LIT:0.0>, axis[<NUM_LIT:0>], axis[<NUM_LIT:1>], axis[<NUM_LIT:2>]])<EOL>qlen = vector_norm(q)<EOL>if qlen > _EPS:<EOL><INDENT>q *= math.sin(angle/<NUM_LIT>) / qlen<EOL><DEDENT>q[<NUM_LIT:0>] = math.cos(angle/<NUM_LIT>)<EOL>return q<EOL>

Return quaternion for rotation about axis.

    >>> q = quaternion_about_axis(0.123, [1, 0, 0])
    >>> numpy.allclose(q, [0.99810947, 0.06146124, 0, 0])
    True


q = numpy.array(quaternion, dtype=numpy.float64, copy=True)<EOL>n = numpy.dot(q, q)<EOL>if n < _EPS:<EOL><INDENT>return numpy.identity(<NUM_LIT:4>)<EOL><DEDENT>q *= math.sqrt(<NUM_LIT> / n)<EOL>q = numpy.outer(q, q)<EOL>return numpy.array([<EOL>[<NUM_LIT:1.0>-q[<NUM_LIT:2>, <NUM_LIT:2>]-q[<NUM_LIT:3>, <NUM_LIT:3>],     q[<NUM_LIT:1>, <NUM_LIT:2>]-q[<NUM_LIT:3>, <NUM_LIT:0>],     q[<NUM_LIT:1>, <NUM_LIT:3>]+q[<NUM_LIT:2>, <NUM_LIT:0>], <NUM_LIT:0.0>],<EOL>[    q[<NUM_LIT:1>, <NUM_LIT:2>]+q[<NUM_LIT:3>, <NUM_LIT:0>], <NUM_LIT:1.0>-q[<NUM_LIT:1>, <NUM_LIT:1>]-q[<NUM_LIT:3>, <NUM_LIT:3>],     q[<NUM_LIT:2>, <NUM_LIT:3>]-q[<NUM_LIT:1>, <NUM_LIT:0>], <NUM_LIT:0.0>],<EOL>[    q[<NUM_LIT:1>, <NUM_LIT:3>]-q[<NUM_LIT:2>, <NUM_LIT:0>],     q[<NUM_LIT:2>, <NUM_LIT:3>]+q[<NUM_LIT:1>, <NUM_LIT:0>], <NUM_LIT:1.0>-q[<NUM_LIT:1>, <NUM_LIT:1>]-q[<NUM_LIT:2>, <NUM_LIT:2>], <NUM_LIT:0.0>],<EOL>[                <NUM_LIT:0.0>,                 <NUM_LIT:0.0>,                 <NUM_LIT:0.0>, <NUM_LIT:1.0>]])<EOL>

Return homogeneous rotation matrix from quaternion.

    >>> M = quaternion_matrix([0.99810947, 0.06146124, 0, 0])
    >>> numpy.allclose(M, rotation_matrix(0.123, [1, 0, 0]))
    True
    >>> M = quaternion_matrix([1, 0, 0, 0])
    >>> numpy.allclose(M, numpy.identity(4))
    True
    >>> M = quaternion_matrix([0, 1, 0, 0])
    >>> numpy.allclose(M, numpy.diag([1, -1, -1, 1]))
    True


M = numpy.array(matrix, dtype=numpy.float64, copy=False)[:<NUM_LIT:4>, :<NUM_LIT:4>]<EOL>if isprecise:<EOL><INDENT>q = numpy.empty((<NUM_LIT:4>, ))<EOL>t = numpy.trace(M)<EOL>if t > M[<NUM_LIT:3>, <NUM_LIT:3>]:<EOL><INDENT>q[<NUM_LIT:0>] = t<EOL>q[<NUM_LIT:3>] = M[<NUM_LIT:1>, <NUM_LIT:0>] - M[<NUM_LIT:0>, <NUM_LIT:1>]<EOL>q[<NUM_LIT:2>] = M[<NUM_LIT:0>, <NUM_LIT:2>] - M[<NUM_LIT:2>, <NUM_LIT:0>]<EOL>q[<NUM_LIT:1>] = M[<NUM_LIT:2>, <NUM_LIT:1>] - M[<NUM_LIT:1>, <NUM_LIT:2>]<EOL><DEDENT>else:<EOL><INDENT>i, j, k = <NUM_LIT:1>, <NUM_LIT:2>, <NUM_LIT:3><EOL>if M[<NUM_LIT:1>, <NUM_LIT:1>] > M[<NUM_LIT:0>, <NUM_LIT:0>]:<EOL><INDENT>i, j, k = <NUM_LIT:2>, <NUM_LIT:3>, <NUM_LIT:1><EOL><DEDENT>if M[<NUM_LIT:2>, <NUM_LIT:2>] > M[i, i]:<EOL><INDENT>i, j, k = <NUM_LIT:3>, <NUM_LIT:1>, <NUM_LIT:2><EOL><DEDENT>t = M[i, i] - (M[j, j] + M[k, k]) + M[<NUM_LIT:3>, <NUM_LIT:3>]<EOL>q[i] = t<EOL>q[j] = M[i, j] + M[j, i]<EOL>q[k] = M[k, i] + M[i, k]<EOL>q[<NUM_LIT:3>] = M[k, j] - M[j, k]<EOL><DEDENT>q *= <NUM_LIT:0.5> / math.sqrt(t * M[<NUM_LIT:3>, <NUM_LIT:3>])<EOL><DEDENT>else:<EOL><INDENT>m00 = M[<NUM_LIT:0>, <NUM_LIT:0>]<EOL>m01 = M[<NUM_LIT:0>, <NUM_LIT:1>]<EOL>m02 = M[<NUM_LIT:0>, <NUM_LIT:2>]<EOL>m10 = M[<NUM_LIT:1>, <NUM_LIT:0>]<EOL>m11 = M[<NUM_LIT:1>, <NUM_LIT:1>]<EOL>m12 = M[<NUM_LIT:1>, <NUM_LIT:2>]<EOL>m20 = M[<NUM_LIT:2>, <NUM_LIT:0>]<EOL>m21 = M[<NUM_LIT:2>, <NUM_LIT:1>]<EOL>m22 = M[<NUM_LIT:2>, <NUM_LIT:2>]<EOL>K = numpy.array([[m00-m11-m22, <NUM_LIT:0.0>,         <NUM_LIT:0.0>,         <NUM_LIT:0.0>],<EOL>[m01+m10,     m11-m00-m22, <NUM_LIT:0.0>,         <NUM_LIT:0.0>],<EOL>[m02+m20,     m12+m21,     m22-m00-m11, <NUM_LIT:0.0>],<EOL>[m21-m12,     m02-m20,     m10-m01,     m00+m11+m22]])<EOL>K /= <NUM_LIT><EOL>w, V = numpy.linalg.eigh(K)<EOL>q = V[[<NUM_LIT:3>, <NUM_LIT:0>, <NUM_LIT:1>, <NUM_LIT:2>], numpy.argmax(w)]<EOL><DEDENT>if q[<NUM_LIT:0>] < <NUM_LIT:0.0>:<EOL><INDENT>numpy.negative(q, q)<EOL><DEDENT>return q<EOL>

Return quaternion from rotation matrix.

    If isprecise is True, the input matrix is assumed to be a precise rotation
    matrix and a faster algorithm is used.

    >>> q = quaternion_from_matrix(numpy.identity(4), True)
    >>> numpy.allclose(q, [1, 0, 0, 0])
    True
    >>> q = quaternion_from_matrix(numpy.diag([1, -1, -1, 1]))
    >>> numpy.allclose(q, [0, 1, 0, 0]) or numpy.allclose(q, [0, -1, 0, 0])
    True
    >>> R = rotation_matrix(0.123, (1, 2, 3))
    >>> q = quaternion_from_matrix(R, True)
    >>> numpy.allclose(q, [0.9981095, 0.0164262, 0.0328524, 0.0492786])
    True
    >>> R = [[-0.545, 0.797, 0.260, 0], [0.733, 0.603, -0.313, 0],
    ...      [-0.407, 0.021, -0.913, 0], [0, 0, 0, 1]]
    >>> q = quaternion_from_matrix(R)
    >>> numpy.allclose(q, [0.19069, 0.43736, 0.87485, -0.083611])
    True
    >>> R = [[0.395, 0.362, 0.843, 0], [-0.626, 0.796, -0.056, 0],
    ...      [-0.677, -0.498, 0.529, 0], [0, 0, 0, 1]]
    >>> q = quaternion_from_matrix(R)
    >>> numpy.allclose(q, [0.82336615, -0.13610694, 0.46344705, -0.29792603])
    True
    >>> R = random_rotation_matrix()
    >>> q = quaternion_from_matrix(R)
    >>> is_same_transform(R, quaternion_matrix(q))
    True
    >>> R = euler_matrix(0.0, 0.0, numpy.pi/2.0)
    >>> numpy.allclose(quaternion_from_matrix(R, isprecise=False),
    ...                quaternion_from_matrix(R, isprecise=True))
    True


w0, x0, y0, z0 = quaternion0<EOL>w1, x1, y1, z1 = quaternion1<EOL>return numpy.array([-x1*x0 - y1*y0 - z1*z0 + w1*w0,<EOL>x1*w0 + y1*z0 - z1*y0 + w1*x0,<EOL>-x1*z0 + y1*w0 + z1*x0 + w1*y0,<EOL>x1*y0 - y1*x0 + z1*w0 + w1*z0], dtype=numpy.float64)<EOL>

Return multiplication of two quaternions.

    >>> q = quaternion_multiply([4, 1, -2, 3], [8, -5, 6, 7])
    >>> numpy.allclose(q, [28, -44, -14, 48])
    True


q = numpy.array(quaternion, dtype=numpy.float64, copy=True)<EOL>numpy.negative(q[<NUM_LIT:1>:], q[<NUM_LIT:1>:])<EOL>return q<EOL>

Return conjugate of quaternion.

    >>> q0 = random_quaternion()
    >>> q1 = quaternion_conjugate(q0)
    >>> q1[0] == q0[0] and all(q1[1:] == -q0[1:])
    True


q = numpy.array(quaternion, dtype=numpy.float64, copy=True)<EOL>numpy.negative(q[<NUM_LIT:1>:], q[<NUM_LIT:1>:])<EOL>return q / numpy.dot(q, q)<EOL>

Return inverse of quaternion.

    >>> q0 = random_quaternion()
    >>> q1 = quaternion_inverse(q0)
    >>> numpy.allclose(quaternion_multiply(q0, q1), [1, 0, 0, 0])
    True


return float(quaternion[<NUM_LIT:0>])<EOL>

Return real part of quaternion.

    >>> quaternion_real([3, 0, 1, 2])
    3.0


return numpy.array(quaternion[<NUM_LIT:1>:<NUM_LIT:4>], dtype=numpy.float64, copy=True)<EOL>

Return imaginary part of quaternion.

    >>> quaternion_imag([3, 0, 1, 2])
    array([ 0.,  1.,  2.])


if rand is None:<EOL><INDENT>rand = numpy.random.rand(<NUM_LIT:3>)<EOL><DEDENT>else:<EOL><INDENT>assert len(rand) == <NUM_LIT:3><EOL><DEDENT>r1 = numpy.sqrt(<NUM_LIT:1.0> - rand[<NUM_LIT:0>])<EOL>r2 = numpy.sqrt(rand[<NUM_LIT:0>])<EOL>pi2 = math.pi * <NUM_LIT><EOL>t1 = pi2 * rand[<NUM_LIT:1>]<EOL>t2 = pi2 * rand[<NUM_LIT:2>]<EOL>return numpy.array([numpy.cos(t2)*r2, numpy.sin(t1)*r1,<EOL>numpy.cos(t1)*r1, numpy.sin(t2)*r2])<EOL>

Return uniform random unit quaternion.

    rand: array like or None
        Three independent random variables that are uniformly distributed
        between 0 and 1.

    >>> q = random_quaternion()
    >>> numpy.allclose(1, vector_norm(q))
    True
    >>> q = random_quaternion(numpy.random.random(3))
    >>> len(q.shape), q.shape[0]==4
    (1, True)


return quaternion_matrix(random_quaternion(rand))<EOL>

Return uniform random rotation matrix.

    rand: array like
        Three independent random variables that are uniformly distributed
        between 0 and 1 for each returned quaternion.

    >>> R = random_rotation_matrix()
    >>> numpy.allclose(numpy.dot(R.T, R), numpy.identity(4))
    True


def arcball_map_to_sphere(point, center, radius):

v0 = (point[<NUM_LIT:0>] - center[<NUM_LIT:0>]) / radius<EOL>v1 = (center[<NUM_LIT:1>] - point[<NUM_LIT:1>]) / radius<EOL>n = v0*v0 + v1*v1<EOL>if n > <NUM_LIT:1.0>:<EOL><INDENT>n = math.sqrt(n)<EOL>return numpy.array([v0/n, v1/n, <NUM_LIT:0.0>])<EOL><DEDENT>else:<EOL><INDENT>return numpy.array([v0, v1, math.sqrt(<NUM_LIT:1.0> - n)])<EOL><DEDENT>

Return unit sphere coordinates from window coordinates.


v = numpy.array(point, dtype=numpy.float64, copy=True)<EOL>a = numpy.array(axis, dtype=numpy.float64, copy=True)<EOL>v -= a * numpy.dot(a, v)  <EOL>n = vector_norm(v)<EOL>if n > _EPS:<EOL><INDENT>if v[<NUM_LIT:2>] < <NUM_LIT:0.0>:<EOL><INDENT>numpy.negative(v, v)<EOL><DEDENT>v /= n<EOL>return v<EOL><DEDENT>if a[<NUM_LIT:2>] == <NUM_LIT:1.0>:<EOL><INDENT>return numpy.array([<NUM_LIT:1.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>])<EOL><DEDENT>return unit_vector([-a[<NUM_LIT:1>], a[<NUM_LIT:0>], <NUM_LIT:0.0>])<EOL>

Return sphere point perpendicular to axis.


point = numpy.array(point, dtype=numpy.float64, copy=False)<EOL>nearest = None<EOL>mx = -<NUM_LIT:1.0><EOL>for axis in axes:<EOL><INDENT>t = numpy.dot(arcball_constrain_to_axis(point, axis), point)<EOL>if t > mx:<EOL><INDENT>nearest = axis<EOL>mx = t<EOL><DEDENT><DEDENT>return nearest<EOL>

Return axis, which arc is nearest to point.


def vector_norm(data, axis=None, out=None):

data = numpy.array(data, dtype=numpy.float64, copy=True)<EOL>if out is None:<EOL><INDENT>if data.ndim == <NUM_LIT:1>:<EOL><INDENT>return math.sqrt(numpy.dot(data, data))<EOL><DEDENT>data *= data<EOL>out = numpy.atleast_1d(numpy.sum(data, axis=axis))<EOL>numpy.sqrt(out, out)<EOL>return out<EOL><DEDENT>else:<EOL><INDENT>data *= data<EOL>numpy.sum(data, axis=axis, out=out)<EOL>numpy.sqrt(out, out)<EOL><DEDENT>

Return length, i.e. Euclidean norm, of ndarray along axis.

    >>> v = numpy.random.random(3)
    >>> n = vector_norm(v)
    >>> numpy.allclose(n, numpy.linalg.norm(v))
    True
    >>> v = numpy.random.rand(6, 5, 3)
    >>> n = vector_norm(v, axis=-1)
    >>> numpy.allclose(n, numpy.sqrt(numpy.sum(v*v, axis=2)))
    True
    >>> n = vector_norm(v, axis=1)
    >>> numpy.allclose(n, numpy.sqrt(numpy.sum(v*v, axis=1)))
    True
    >>> v = numpy.random.rand(5, 4, 3)
    >>> n = numpy.empty((5, 3))
    >>> vector_norm(v, axis=1, out=n)
    >>> numpy.allclose(n, numpy.sqrt(numpy.sum(v*v, axis=1)))
    True
    >>> vector_norm([])
    0.0
    >>> vector_norm([1])
    1.0


def unit_vector(data, axis=None, out=None):

if out is None:<EOL><INDENT>data = numpy.array(data, dtype=numpy.float64, copy=True)<EOL>if data.ndim == <NUM_LIT:1>:<EOL><INDENT>data /= math.sqrt(numpy.dot(data, data))<EOL>return data<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if out is not data:<EOL><INDENT>out[:] = numpy.array(data, copy=False)<EOL><DEDENT>data = out<EOL><DEDENT>length = numpy.atleast_1d(numpy.sum(data*data, axis))<EOL>numpy.sqrt(length, length)<EOL>if axis is not None:<EOL><INDENT>length = numpy.expand_dims(length, axis)<EOL><DEDENT>data /= length<EOL>if out is None:<EOL><INDENT>return data<EOL><DEDENT>

Return ndarray normalized by length, i.e. Euclidean norm, along axis.

    >>> v0 = numpy.random.random(3)
    >>> v1 = unit_vector(v0)
    >>> numpy.allclose(v1, v0 / numpy.linalg.norm(v0))
    True
    >>> v0 = numpy.random.rand(5, 4, 3)
    >>> v1 = unit_vector(v0, axis=-1)
    >>> v2 = v0 / numpy.expand_dims(numpy.sqrt(numpy.sum(v0*v0, axis=2)), 2)
    >>> numpy.allclose(v1, v2)
    True
    >>> v1 = unit_vector(v0, axis=1)
    >>> v2 = v0 / numpy.expand_dims(numpy.sqrt(numpy.sum(v0*v0, axis=1)), 1)
    >>> numpy.allclose(v1, v2)
    True
    >>> v1 = numpy.empty((5, 4, 3))
    >>> unit_vector(v0, axis=1, out=v1)
    >>> numpy.allclose(v1, v2)
    True
    >>> list(unit_vector([]))
    []
    >>> list(unit_vector([1]))
    [1.0]


return numpy.random.random(size)<EOL>

Return array of random doubles in the half-open interval [0.0, 1.0).

    >>> v = random_vector(10000)
    >>> numpy.all(v >= 0) and numpy.all(v < 1)
    True
    >>> v0 = random_vector(10)
    >>> v1 = random_vector(10)
    >>> numpy.any(v0 == v1)
    False


def vector_product(v0, v1, axis=<NUM_LIT:0>):

return numpy.cross(v0, v1, axis=axis)<EOL>


def angle_between_vectors(v0, v1, directed=True, axis=<NUM_LIT:0>):

v0 = numpy.array(v0, dtype=numpy.float64, copy=False)<EOL>v1 = numpy.array(v1, dtype=numpy.float64, copy=False)<EOL>dot = numpy.sum(v0 * v1, axis=axis)<EOL>dot /= vector_norm(v0, axis=axis) * vector_norm(v1, axis=axis)<EOL>return numpy.arccos(dot if directed else numpy.fabs(dot))<EOL>


return numpy.linalg.inv(matrix)<EOL>

Return inverse of square transformation matrix.

    >>> M0 = random_rotation_matrix()
    >>> M1 = inverse_matrix(M0.T)
    >>> numpy.allclose(M1, numpy.linalg.inv(M0.T))
    True
    >>> for size in range(1, 7):
    ...     M0 = numpy.random.rand(size, size)
    ...     M1 = inverse_matrix(M0)
    ...     if not numpy.allclose(M1, numpy.linalg.inv(M0)): print(size)


M = numpy.identity(<NUM_LIT:4>)<EOL>for i in matrices:<EOL><INDENT>M = numpy.dot(M, i)<EOL><DEDENT>return M<EOL>

Return concatenation of series of transformation matrices.

    >>> M = numpy.random.rand(16).reshape((4, 4)) - 0.5
    >>> numpy.allclose(M, concatenate_matrices(M))
    True
    >>> numpy.allclose(numpy.dot(M, M.T), concatenate_matrices(M, M.T))
    True


matrix0 = numpy.array(matrix0, dtype=numpy.float64, copy=True)<EOL>matrix0 /= matrix0[<NUM_LIT:3>, <NUM_LIT:3>]<EOL>matrix1 = numpy.array(matrix1, dtype=numpy.float64, copy=True)<EOL>matrix1 /= matrix1[<NUM_LIT:3>, <NUM_LIT:3>]<EOL>return numpy.allclose(matrix0, matrix1)<EOL>

Return True if two matrices perform same transformation.

    >>> is_same_transform(numpy.identity(4), numpy.identity(4))
    True
    >>> is_same_transform(numpy.identity(4), random_rotation_matrix())
    False


def _import_module(name, package=None, warn=True, prefix='<STR_LIT>', ignore='<STR_LIT:_>'):

import warnings<EOL>from importlib import import_module<EOL>try:<EOL><INDENT>if not package:<EOL><INDENT>module = import_module(name)<EOL><DEDENT>else:<EOL><INDENT>module = import_module('<STR_LIT:.>' + name, package=package)<EOL><DEDENT><DEDENT>except ImportError:<EOL><INDENT>if warn:<EOL><INDENT>warnings.warn("<STR_LIT>" % name)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>for attr in dir(module):<EOL><INDENT>if ignore and attr.startswith(ignore):<EOL><INDENT>continue<EOL><DEDENT>if prefix:<EOL><INDENT>if attr in globals():<EOL><INDENT>globals()[prefix + attr] = globals()[attr]<EOL><DEDENT>elif warn:<EOL><INDENT>warnings.warn("<STR_LIT>" + attr)<EOL><DEDENT><DEDENT>globals()[attr] = getattr(module, attr)<EOL><DEDENT>return True<EOL><DEDENT>

Try import all public attributes from module into global namespace.

    Existing attributes with name clashes are renamed with prefix.
    Attributes starting with underscore are ignored by default.

    Return True on successful import.


self._axis = None<EOL>self._axes = None<EOL>self._radius = <NUM_LIT:1.0><EOL>self._center = [<NUM_LIT:0.0>, <NUM_LIT:0.0>]<EOL>self._vdown = numpy.array([<NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:1.0>])<EOL>self._constrain = False<EOL>if initial is None:<EOL><INDENT>self._qdown = numpy.array([<NUM_LIT:1.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>])<EOL><DEDENT>else:<EOL><INDENT>initial = numpy.array(initial, dtype=numpy.float64)<EOL>if initial.shape == (<NUM_LIT:4>, <NUM_LIT:4>):<EOL><INDENT>self._qdown = quaternion_from_matrix(initial)<EOL><DEDENT>elif initial.shape == (<NUM_LIT:4>, ):<EOL><INDENT>initial /= vector_norm(initial)<EOL>self._qdown = initial<EOL><DEDENT>else:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT><DEDENT>self._qnow = self._qpre = self._qdown<EOL>

Initialize virtual trackball control.

        initial : quaternion or rotation matrix


self._radius = float(radius)<EOL>self._center[<NUM_LIT:0>] = center[<NUM_LIT:0>]<EOL>self._center[<NUM_LIT:1>] = center[<NUM_LIT:1>]<EOL>

Place Arcball, e.g. when window size changes.

        center : sequence[2]
            Window coordinates of trackball center.
        radius : float
            Radius of trackball in window coordinates.


if axes is None:<EOL><INDENT>self._axes = None<EOL><DEDENT>else:<EOL><INDENT>self._axes = [unit_vector(axis) for axis in axes]<EOL><DEDENT>


return self._constrain<EOL>


self._constrain = bool(value)<EOL>


self._vdown = arcball_map_to_sphere(point, self._center, self._radius)<EOL>self._qdown = self._qpre = self._qnow<EOL>if self._constrain and self._axes is not None:<EOL><INDENT>self._axis = arcball_nearest_axis(self._vdown, self._axes)<EOL>self._vdown = arcball_constrain_to_axis(self._vdown, self._axis)<EOL><DEDENT>else:<EOL><INDENT>self._axis = None<EOL><DEDENT>

Set initial cursor window coordinates and pick constrain-axis.


vnow = arcball_map_to_sphere(point, self._center, self._radius)<EOL>if self._axis is not None:<EOL><INDENT>vnow = arcball_constrain_to_axis(vnow, self._axis)<EOL><DEDENT>self._qpre = self._qnow<EOL>t = numpy.cross(self._vdown, vnow)<EOL>if numpy.dot(t, t) < _EPS:<EOL><INDENT>self._qnow = self._qdown<EOL><DEDENT>else:<EOL><INDENT>q = [numpy.dot(self._vdown, vnow), t[<NUM_LIT:0>], t[<NUM_LIT:1>], t[<NUM_LIT:2>]]<EOL>self._qnow = quaternion_multiply(q, self._qdown)<EOL><DEDENT>

Update current cursor window coordinates.


q = quaternion_slerp(self._qpre, self._qnow, <NUM_LIT>+acceleration, False)<EOL>self._qpre, self._qnow = self._qnow, q<EOL>

Continue rotation in direction of last drag.


return quaternion_matrix(self._qnow)<EOL>


return self.window.wait()<EOL>

Block until a browser is connected to the server


<EOL>repo_dir = Path(__file__).parent.absolute()<EOL>source_dir = Path(repo_dir, package.__name__)<EOL>if source_dir.exists():<EOL><INDENT>print("<STR_LIT>" % source_dir)<EOL>print("<STR_LIT>")<EOL>source_dir.autopep8(**kwargs)<EOL><DEDENT>else:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT>unittest_dir = Path(repo_dir, "<STR_LIT>")<EOL>if unittest_dir.exists():<EOL><INDENT>print("<STR_LIT>" % unittest_dir)<EOL>print("<STR_LIT>")<EOL>unittest_dir.autopep8(**kwargs)<EOL><DEDENT>else:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT>print("<STR_LIT>")<EOL>

auto pep8 format all python file in ``source code`` and ``tests`` dir.


return getfullargspec(func).defaults[<NUM_LIT:0>]<EOL>

Get default value of ``class_name`` argument.

    Because the third argument of dumper, loader method must be the class name.


if getfullargspec(func).args == ["<STR_LIT>", "<STR_LIT>", "<STR_LIT>"]:<EOL><INDENT>return True<EOL><DEDENT>else:<EOL><INDENT>return False<EOL><DEDENT>


abspath = abspath.lower()<EOL>fname, ext = os.path.splitext(abspath)<EOL>if ext in ["<STR_LIT>", "<STR_LIT>"]:<EOL><INDENT>is_compressed = False<EOL><DEDENT>elif ext == "<STR_LIT>":<EOL><INDENT>is_compressed = True<EOL><DEDENT>else:<EOL><INDENT>raise ValueError(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>" % abspath)<EOL><DEDENT>return is_compressed<EOL>

Test a file is a valid json file.

    - *.json: uncompressed, utf-8 encode json file
    - *.js: uncompressed, utf-8 encode json file
    - *.gz: compressed, utf-8 encode json file


class_name = get_class_name(obj)<EOL>if class_name in self._dumpers:<EOL><INDENT>return self._dumpers[class_name](self, obj)<EOL><DEDENT>raise TypeError("<STR_LIT>" % obj)<EOL>

Dump single object to json serializable value.


<EOL>if isinstance(obj, OrderedDict):<EOL><INDENT>try:<EOL><INDENT>return self._dump(obj)<EOL><DEDENT>except TypeError:<EOL><INDENT>return {k: self._json_convert(v) for k, v in iteritems(obj)}<EOL><DEDENT><DEDENT>elif isinstance(obj, dict):<EOL><INDENT>return {k: self._json_convert(v) for k, v in iteritems(obj)}<EOL><DEDENT>elif isinstance(obj, (list, tuple)):<EOL><INDENT>return list((self._json_convert(v) for v in obj))<EOL><DEDENT>elif isinstance(obj, float):<EOL><INDENT>return float(json.encoder.FLOAT_REPR(obj))<EOL><DEDENT>try:<EOL><INDENT>return self._dump(obj)<EOL><DEDENT>except TypeError:<EOL><INDENT>return obj<EOL><DEDENT>

Recursive helper method that converts dict types to standard library
        json serializable types, so they can be converted into json.


<EOL>if len(dct) == <NUM_LIT:1>:<EOL><INDENT>for key, value in iteritems(dct):<EOL><INDENT>class_name = key[<NUM_LIT:1>:]<EOL>if class_name in self._loaders:<EOL><INDENT>return self._loaders[class_name](self, dct)<EOL><DEDENT><DEDENT>return dct<EOL><DEDENT>return dct<EOL>

A function can convert dict data into object.

        it's an O(1) implementation.


for class_name, loader in self._loaders.items():<EOL><INDENT>if ("<STR_LIT:$>" + class_name) in dct:<EOL><INDENT>return loader(self, dct)<EOL><DEDENT><DEDENT>return dct<EOL>

Another object hook implementation.

        it's an O(N) implementation.


if pretty:<EOL><INDENT>indent = <NUM_LIT:4><EOL>sort_keys = True<EOL><DEDENT>if float_precision is None:<EOL><INDENT>json.encoder.FLOAT_REPR = repr<EOL><DEDENT>else:<EOL><INDENT>json.encoder.FLOAT_REPR = lambda x: format(<EOL>x, "<STR_LIT>" % float_precision)<EOL><DEDENT>s = json.dumps(<EOL>self._json_convert(obj),<EOL>indent=indent,<EOL>sort_keys=sort_keys,<EOL>ensure_ascii=ensure_ascii,<EOL>**kwargs<EOL>)<EOL>if compress:<EOL><INDENT>s = compresslib.compress(s, return_type="<STR_LIT:str>")<EOL><DEDENT>return s<EOL>

Dump any object into json string.

        :param pretty: if True, dump json into pretty indent and sorted key
          format.
        :type pretty: bool

        :param float_precision: default ``None``, limit floats to
          N-decimal points.
        :type float_precision: integer

        :param compress: default ``False. If True, then compress encoded string.
        :type compress: bool


if decompress:<EOL><INDENT>s = compresslib.decompress(s, return_type="<STR_LIT:str>")<EOL><DEDENT>if ignore_comments:<EOL><INDENT>s = strip_comments(s)<EOL><DEDENT>if object_hook is None:<EOL><INDENT>object_hook = self._object_hook1<EOL><DEDENT>if "<STR_LIT>" in kwargs:<EOL><INDENT>del kwargs["<STR_LIT>"]<EOL><DEDENT>obj = json.loads(<EOL>s,<EOL>object_hook=object_hook,<EOL>object_pairs_hook=None,<EOL>**kwargs<EOL>)<EOL>return obj<EOL>

load object from json encoded string.

        :param decompress: default ``False. If True, then decompress string.
        :type decompress: bool

        :param ignore_comments: default ``False. If True, then ignore comments.
        :type ignore_comments: bool


prt_console("<STR_LIT>" % abspath, verbose)<EOL>is_compressed = is_compressed_json_file(abspath)<EOL>if not overwrite:<EOL><INDENT>if os.path.exists(abspath):  <EOL><INDENT>prt_console(<EOL>"<STR_LIT>",<EOL>verbose,<EOL>)<EOL>return<EOL><DEDENT><DEDENT>st = time.clock()<EOL>s = self.dumps(<EOL>obj,<EOL>indent=indent,<EOL>sort_keys=sort_keys,<EOL>pretty=pretty,<EOL>float_precision=float_precision,<EOL>ensure_ascii=ensure_ascii,<EOL>compress=False,  <EOL>**kwargs<EOL>)<EOL>with atomic_write(abspath, mode="<STR_LIT:wb>", overwrite=True) as f:<EOL><INDENT>if is_compressed:<EOL><INDENT>f.write(compresslib.compress(s, return_type="<STR_LIT>"))<EOL><DEDENT>else:<EOL><INDENT>f.write(s.encode("<STR_LIT:utf-8>"))<EOL><DEDENT><DEDENT>prt_console(<EOL>"<STR_LIT>" % (time.clock() - st),<EOL>verbose,<EOL>)<EOL>return s<EOL>

Dump any object into file.

        :param abspath: if ``*.json, *.js** then do regular dump. if ``*.gz``,
          then perform compression.
        :type abspath: str

        :param pretty: if True, dump json into pretty indent and sorted key
          format.
        :type pretty: bool

        :param float_precision: default ``None``, limit floats to
          N-decimal points.
        :type float_precision: integer

        :param overwrite: default ``False``, If ``True``, when you dump to
          existing file, it silently overwrite it. If ``False``, an alert
          message is shown. Default setting ``False`` is to prevent overwrite
          file by mistake.
        :type overwrite: boolean

        :param verbose: default True, help-message-display trigger.
        :type verbose: boolean


prt_console("<STR_LIT>" % abspath, verbose)<EOL>is_compressed = is_compressed_json_file(abspath)<EOL>if not os.path.exists(abspath):<EOL><INDENT>raise EnvironmentError("<STR_LIT>" % abspath)<EOL><DEDENT>st = time.clock()<EOL>with open(abspath, "<STR_LIT:rb>") as f:<EOL><INDENT>if is_compressed:<EOL><INDENT>s = compresslib.decompress(f.read(), return_type="<STR_LIT:str>")<EOL><DEDENT>else:<EOL><INDENT>s = f.read().decode("<STR_LIT:utf-8>")<EOL><DEDENT><DEDENT>obj = self.loads(<EOL>s,<EOL>object_hook=object_hook,<EOL>decompress=False,<EOL>ignore_comments=ignore_comments,<EOL>)<EOL>prt_console("<STR_LIT>" % (time.clock() - st),<EOL>verbose)<EOL>return obj<EOL>

load object from json file.

        :param abspath: if ``*.json, *.js** then do regular dump. if ``*.gz``,
          then perform decompression.
        :type abspath: str

        :param ignore_comments: default ``False. If True, then ignore comments.
        :type ignore_comments: bool

        :param verbose: default True, help-message-display trigger.
        :type verbose: boolean


def dump_bytes(self, obj, class_name=bytes_class_name):

return {"<STR_LIT:$>" + class_name: b64encode(obj).decode()}<EOL>


def load_bytes(self, dct, class_name=bytes_class_name):

return b64decode(dct["<STR_LIT:$>" + class_name].encode())<EOL>


def dump_datetime(self, obj, class_name="<STR_LIT>"):

return {"<STR_LIT:$>" + class_name: obj.isoformat()}<EOL>


def load_datetime(self, dct, class_name="<STR_LIT>"):

return parse(dct["<STR_LIT:$>" + class_name])<EOL>


def dump_date(self, obj, class_name="<STR_LIT>"):

return {"<STR_LIT:$>" + class_name: str(obj)}<EOL>


def load_date(self, dct, class_name="<STR_LIT>"):

return datetime.strptime(dct["<STR_LIT:$>" + class_name], "<STR_LIT>").date()<EOL>


def dump_set(self, obj, class_name=set_class_name):

return {"<STR_LIT:$>" + class_name: [self._json_convert(item) for item in obj]}<EOL>


def load_set(self, dct, class_name=set_class_name):

return set(dct["<STR_LIT:$>" + class_name])<EOL>


def dump_deque(self, obj, class_name="<STR_LIT>"):


def load_deque(self, dct, class_name="<STR_LIT>"):

return deque(dct["<STR_LIT:$>" + class_name])<EOL>


def dump_OrderedDict(self, obj, class_name="<STR_LIT>"):

return {<EOL>"<STR_LIT:$>" + class_name: [<EOL>(key, self._json_convert(value)) for key, value in iteritems(obj)<EOL>]<EOL>}<EOL>


def load_OrderedDict(self, dct, class_name="<STR_LIT>"):

return OrderedDict(dct["<STR_LIT:$>" + class_name])<EOL>


def dump_nparray(self, obj, class_name=numpy_ndarray_class_name):

return {"<STR_LIT:$>" + class_name: self._json_convert(obj.tolist())}<EOL>


def load_nparray(self, dct, class_name=numpy_ndarray_class_name):

return np.array(dct["<STR_LIT:$>" + class_name])<EOL>


def dump_pathlib_path(self, obj, class_name=pathlib_path_class_name):

``pathlib.Path`` or ``pathlib2.Path`` dumper.