Skip to content

Commit

Permalink
Add eclipse megamovie rendering code.
Browse files Browse the repository at this point in the history
  • Loading branch information
David Konerding committed Oct 4, 2017
1 parent 4263f8f commit 0fce4e0
Show file tree
Hide file tree
Showing 34 changed files with 4,419 additions and 0 deletions.
Binary file not shown.
20 changes: 20 additions & 0 deletions src/solar_eclipse_analysis/README.md
@@ -0,0 +1,20 @@
Create conf.sh:

PROJECT_ID= # name of GCP project
IMAGE_BUCKET=megamovie # name of image_bucket to select images from
OUTPUT= # where to write output data, filesystem needs ~1TB free space
IMAGE_DIR= # directory containing all the input images
PHOTO_TABLE=Photo # Name of the photo table
MAP_DIR=$OUTPUT/map # where map output will be written
RESCALED_DIR=$OUTPUT/rescaled # where rescaled images will be written
CIRCLES_DIR=$OUTPUT/circles # where detected circles will be written
CLASSIFY_DIR=$OUTPUT/classify # where cloud vision classifications will be written
CREDITS_DIR=$OUTPUT/credits # where the credits output will be written
MOVIE_DIR=$OUTPUT/movie # where the movie output files will be written
MOVIE_RENUMBER_DIR=$OUTPUT/movie_renumber # where the renumbered movie files will be written
PARTITION_DIR=$OUTPUT/partition # where thre partitioned movie files will be written
FINAL_DIR=$OUTPUT/final # final directory where output files will appear
SELECTED_DIR=$OUTPUT/selected # where the list of selected images will be written
VIDEO_SETTINGS="-c:v libx264 -preset slow -crf 8" # video settings for movie encoding

Run make_movie.sh.
173 changes: 173 additions & 0 deletions src/solar_eclipse_analysis/choose_movie_frames.py
@@ -0,0 +1,173 @@
#
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import pprint
import shutil
import glob
import functools
import traceback
import tempfile
import StringIO
import pickle
import os
import numpy as np
import string
import argparse
import cv2
from find_circles import findCircles
from rescale_photos import process_image
from map_util import load_path, points_to_latlong
from multiprocessing import Pool
from PIL import Image, ImageDraw, ImageFont
import matplotlib.cm as cm
import matplotlib # Force matplotlib to not use any Xwindows backend
matplotlib.use('Agg')
from matplotlib import pyplot as plt
from mpl_toolkits.basemap import Basemap
from functools import partial
from rawkit.raw import Raw
from collections import Counter
RES_X=1920
RES_Y=1080


c = Counter()

def get_arguments():
parser = argparse.ArgumentParser(description='Render movie.')
parser.add_argument('--directory', type=str, default="")
parser.add_argument('--metadata', type=str, default="extracted_metadata.pkl")
parser.add_argument('--umbra_polys', type=str, default='umbra_polys.pkl')
parser.add_argument('--photo_selections', type=str, default='photo_selections.pkl')
parser.add_argument('--rescaled_directory', type=str, default="rescaled")
parser.add_argument('--movie_blacklist', type=str, default="data/movie_blacklist.txt")
parser.add_argument('--movie_stats', type=str, default="movie_stats.txt")
parser.add_argument('--movie_frame_choices', type=str, default="movie_frame_choices.pkl")
return parser.parse_args()

def get_rescaled(fname, metadata, directory, rescaled_directory):
# TODO(dek): move rescaling to its own function
rescaled_fname = fname + ".rescaled.png"
rescaled = os.path.join(rescaled_directory, rescaled_fname)
if not os.path.exists(rescaled):
print "Unable to find cached rescaled image for", fname
return None
image = cv2.imread(rescaled, cv2.IMREAD_UNCHANGED)
if image is None:
print "Failed to read image from", rescaled
return None
b_channel, g_channel, r_channel = cv2.split(image)
alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255
image = cv2.merge((b_channel, g_channel, r_channel, alpha_channel))

return image

def get_photo_selection(photo_selections, i):
counter = i
while counter >= 0:
if photo_selections.has_key(counter) and photo_selections[counter] is not None:
return photo_selections[counter]
counter -= 1
return None


def filter_rescaled_photo_selections(i, photo_selections, rescaled_photos):
print "Frame", i
photo_selection = get_photo_selection(photo_selections, i)
results = []
if photo_selection is not None:
for j in range(len(photo_selection)):
fname = photo_selection[j][1]
if fname in rescaled_photos:
results.append(photo_selection[j])

return i, results

def choose_movie_frame(i, rescaled_photo_selection, metadata):
if len(rescaled_photo_selection) == 0:
return i, None
for rescaled_photo in rescaled_photo_selection:
fname = rescaled_photo[1]
# if metadata.has_key(fname):
# eq = metadata[fname].get('equatorial_mount', False)
# if eq == False:
# print "Skipping", fname, "due to non-equatorial mount"
# continue
c.update([fname])
if c[fname] > 8:
print "Skipping", fname, "due to threshold"
continue
else:
print "Selecting", fname
return i, rescaled_photo
else:
print "Exhausted, selecting last"
return i, rescaled_photo_selection[-1]



def main():
args = get_arguments()
photo_selections = pickle.load(open(args.photo_selections))
movie_blacklist = [line.strip() for line in open(args.movie_blacklist).readlines()]

s = set()
frame = photo_selections.values()
for photos in frame:
for photo in photos:
fname = photo[1]
if fname not in movie_blacklist:
s.add(photo[1])

print "Total of", len(s), "photos"
fnames = list(s)
fnames.sort()

rescaled_photos = set()
for fname in fnames:
f = os.path.join(args.rescaled_directory, fname + ".rescaled.png")
if os.path.exists(f):
rescaled_photos.add(fname)

print "Total of", len(rescaled_photos), "rescaled photos"

polys = pickle.load(open(args.umbra_polys))
blahs = []
metadata = pickle.load(open(args.metadata))
rescaled_photo_selections = []
for i, poly in enumerate(polys):
rescaled_photo_selections.append(filter_rescaled_photo_selections(i, photo_selections, rescaled_photos))

rescaled_photo_selections = dict(rescaled_photo_selections)

movie_frames = []
for i, poly in enumerate(polys):
movie_frames.append(choose_movie_frame(i, rescaled_photo_selections[i], metadata))
movie_frames = dict(movie_frames)

pickle.dump(movie_frames, open(args.movie_frame_choices, "wb"))

f = open(args.movie_stats, "wb")
keys = movie_frames.keys()
keys.sort()
for key in keys:
movie_frame = movie_frames[key]
if movie_frame is None: continue
dist, fname, photo_lat, photo_lon, image_datetime, width, height = movie_frame
f.write("%d %s %f %f\n" % (key, fname, photo_lat, photo_lon))
f.close()

if __name__ == '__main__':
main()
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/solar_eclipse_analysis/data/Map_pin.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/solar_eclipse_analysis/data/berkeley_logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 47 additions & 0 deletions src/solar_eclipse_analysis/data/eclipse_path_data.txt
@@ -0,0 +1,47 @@
17:17 45 17.2N 123 57.9W 44 23.8N 124 05.3W 44 50.5N 124 03.7W 1.028 39 115 99 01m57.3s
17:18 45 16.2N 123 26.5W 44 21.0N 122 58.9W 44 48.6N 123 12.3W 1.029 39 116 99 01m57.3s
17:20 45 11.9N 121 50.6W 44 16.0N 121 26.0W 44 44.0N 121 38.0W 1.029 41 118 99 01m57.3s
17:22 45 06.6N 120 18.3W 44 10.0N 119 56.6W 44 38.3N 120 07.2W 1.029 42 120 99 01m57.3s
17:24 45 00.4N 118 49.2W 44 03.2N 118 30.4W 44 31.8N 118 39.5W 1.029 43 122 99 01m57.3s
17:26 44 53.3N 117 23.1W 43 55.6N 117 07.0W 44 24.4N 117 14.8W 1.030 44 124 99 01m57.3s
17:28 44 45.3N 115 59.8W 43 47.2N 115 46.3W 44 16.3N 115 52.8W 1.030 46 126 99 01m57.3s
17:30 44 36.7N 114 39.0W 43 38.2N 114 28.1W 44 07.4N 114 33.3W 1.030 47 128 99 01m57.3s
17:32 44 27.3N 113 20.7W 43 28.5N 113 12.2W 43 57.9N 113 16.2W 1.030 48 130 99 01m57.3s
17:34 44 17.3N 112 04.6W 43 18.2N 111 58.5W 43 47.7N 112 01.3W 1.031 49 132 99 01m57.3s
17:36 44 06.6N 110 50.5W 43 07.3N 110 46.8W 43 37.0N 110 48.5W 1.031 50 134 99 01m57.3s
17:38 43 55.4N 109 38.5W 42 55.8N 109 37.0W 43 25.6N 109 37.6W 1.031 51 136 99 01m57.3s
17:40 43 43.6N 108 28.3W 42 43.9N 108 29.0W 43 13.7N 108 28.5W 1.031 52 138 99 01m57.3s
17:42 43 31.3N 107 19.9W 42 31.4N 107 22.6W 43 01.3N 107 21.1W 1.031 53 141 99 01m57.3s
17:44 43 18.4N 106 13.1W 42 18.5N 106 17.9W 42 48.5N 106 15.4W 1.031 54 143 99 01m57.3s
17:46 43 05.1N 105 07.9W 42 05.2N 105 14.6W 42 35.1N 105 11.2W 1.031 54 145 99 01m57.3s
17:48 42 51.3N 104 04.2W 41 51.4N 104 12.8W 42 21.3N 104 08.4W 1.032 55 147 99 01m57.3s
17:50 42 37.1N 103 01.9W 41 37.2N 103 12.3W 42 07.1N 103 07.0W 1.032 56 149 99 01m57.3s
17:52 42 22.5N 102 00.9W 41 22.6N 102 13.1W 41 52.5N 102 06.9W 1.032 57 152 99 01m57.3s
17:54 42 07.4N 101 01.2W 41 07.7N 101 15.1W 41 37.5N 101 08.1W 1.032 58 154 99 01m57.3s
17:56 41 52.0N 100 02.6W 40 52.3N 100 18.2W 41 22.1N 100 10.4W 1.032 58 157 99 01m57.3s
17:58 41 36.2N 99 05.2W 40 36.7N 99 22.4W 41 06.4N 99 13.8W 1.032 59 159 99 01m57.3s
18:00 41 20.0N 98 08.9W 40 20.6N 98 27.7W 40 50.3N 98 18.3W 1.032 59 162 99 01m57.3s
18:02 41 03.5N 97 13.6W 40 04.3N 97 33.9W 40 33.9N 97 23.7W 1.032 60 164 99 01m57.3s
18:04 40 46.6N 96 19.3W 39 47.6N 96 41.0W 40 17.1N 96 30.1W 1.032 61 167 99 01m57.3s
18:06 40 29.4N 95 25.9W 39 30.7N 95 49.0W 40 00.0N 95 37.4W 1.032 61 169 99 01m57.3s
18:08 40 11.9N 94 33.3W 39 13.4N 94 57.8W 39 42.6N 94 45.6W 1.032 61 172 99 01m57.3s
18:10 39 54.1N 93 41.6W 38 55.8N 94 07.3W 39 24.9N 93 54.5W 1.032 62 175 99 01m57.3s
18:12 39 35.9N 92 50.6W 38 38.0N 93 17.6W 39 07.0N 93 04.2W 1.033 62 178 99 01m57.3s
18:14 39 17.5N 92 00.4W 38 19.9N 92 28.6W 38 48.7N 92 14.6W 1.033 63 181 99 01m57.3s
18:16 38 58.8N 91 10.9W 38 01.5N 91 40.3W 38 30.1N 91 25.6W 1.033 63 183 99 01m57.3s
18:18 38 39.8N 90 22.0W 37 42.8N 90 52.5W 38 11.3N 90 37.3W 1.033 63 186 99 01m57.3s
18:20 38 20.5N 89 33.7W 37 23.9N 90 05.3W 37 52.2N 89 49.6W 1.033 63 189 99 01m57.3s
18:22 38 00.9N 88 46.0W 37 04.7N 89 18.6W 37 32.8N 89 02.4W 1.033 63 192 99 01m57.3s
18:24 37 41.1N 87 58.8W 36 45.2N 88 32.5W 37 13.2N 88 15.7W 1.033 63 195 99 01m57.3s
18:26 37 21.0N 87 12.1W 36 25.5N 87 46.7W 36 53.3N 87 29.5W 1.033 63 198 99 01m57.3s
18:28 37 00.7N 86 25.9W 36 05.6N 87 01.4W 36 33.1N 86 43.7W 1.033 63 201 99 01m57.3s
18:30 36 40.1N 85 40.0W 35 45.4N 86 16.4W 36 12.7N 85 58.3W 1.033 63 204 99 01m57.3s
18:32 36 19.2N 84 54.6W 35 24.9N 85 31.8W 35 52.1N 85 13.3W 1.033 63 207 99 01m57.3s
18:34 35 58.1N 84 09.4W 35 04.2N 84 47.5W 35 31.2N 84 28.6W 1.032 63 210 99 01m57.3s
18:36 35 36.7N 83 24.6W 34 43.3N 84 03.5W 35 10.0N 83 44.1W 1.032 63 212 99 01m57.3s
18:38 35 15.1N 82 40.0W 34 22.1N 83 19.6W 34 48.6N 82 59.9W 1.032 62 215 99 01m57.3s
18:40 34 53.2N 81 55.6W 34 00.6N 82 36.0W 34 26.9N 82 15.9W 1.032 62 218 99 01m57.3s
18:42 34 31.1N 81 11.4W 33 39.0N 81 52.5W 34 05.0N 81 32.1W 1.032 62 221 99 01m57.3s
18:44 34 08.7N 80 27.4W 33 17.0N 81 09.2W 33 42.9N 80 48.4W 1.032 61 223 99 01m57.3s
18:46 33 46.0N 79 43.4W 32 54.9N 80 25.9W 33 20.5N 80 04.7W 1.032 61 226 99 01m57.3s
18:47 33 26.8N 79 06.5W 32 39.4N 79 56.1W 33 00.6N 79 26.6W 1.032 61 228 99 01m57.3s
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
103 changes: 103 additions & 0 deletions src/solar_eclipse_analysis/data/movie_blacklist.txt
@@ -0,0 +1,103 @@
bde09e5e08a2d86b5475f7924afef14a7d544ced129bb3c64eb2a3ed98314278
26380fb70562727baa42214bad043636d9c24d377c1ae29b24d1ae06d46cdb15
26380fb70562727baa42214bad043636d9c24d377c1ae29b24d1ae06d46cdb15
349260ab56d3ba890b574ac7de6c0977f3c2d2f33df3da940f0a0415a24af6fe
53566282067feaeb8aef42a5652e852636f0df257bcabeeac7205621a4707ca7
8b676d116d09ba829a22ca8ccdbb7fbeb09c41e1ab1df65890819d0ccb100947
a5f8478232a8f529f0ccaae3e8efa7ad7c4008068b75e986bc53cd13ecb45b33
beadd8326f0f9da8c5b22a1efaf43ae17693152979fec6fb0f63e4a8438c9d12
1bb5cb7491eb4cc7a9c9ea305043aedd4d86f8795814b062627819cf5f5d6aa3
703404ba0e706f06c4b2c5b3f6c89d7fec8cdb750e2c897ca8ad40a30fa8c9e1
09a04bc21a29e575d6f185ca4274157f1ce1cca0506a286e997335684167ca7c
097db2ec62a07b8ffd2ca6b318f446b7eb199909ccb3936359078f88a9f61c44
97982fc4395f7978b3fe0a0f9d38b8def008c18d70c18dd855c4914b9d620b59
8725c6681e8c87fe068da00164496cfdba9a57902db757dc786681a1e47d5566
097db2ec62a07b8ffd2ca6b318f446b7eb199909ccb3936359078f88a9f61c44
6116520f0ca7eff8337074cd773c48babcdd546c9e16c72d0aa867ac9b447de1
1dd4b5f4e3e7eceaf54b4bc11324b36fe878590a4880f2ba4ab355c380dc2b6d
7b154bba8b6b9eec78d71ca9cf54c461cd7ad177dbdc8f8879226858dce003af
0ccad9be8a73283897e0c2e317e329f1f9a102e8b6290aab7e204cbf29f385a5
1b11e76f9c8993217ddfba95c48abbbb066e0492a10bf419507deb67bfe57e12
1e2851d520d87b0876c02c919b656bcd071b4110f9168054435ab010dbde7026
2c6a0967278ada65349a83a904778e3e13d7ac93d80d7017b1916d2a69a950c9
2fd35a843aba5cb81a456a8cfb639bce8f82e434aef193c7242007d4e920976e
3e6f94b347e9019ccbfbc22c2f7a8a08e7028674b2a6e7092a77eea0d52b468a
4a38d4ede461fd2af6e55fa203eb27c768941be75006e45e3d0becfe9a46760f
4c07c4b8355f774fa3b18b267a1e693cb6839de30670c4552d1565cc59986eef
4c883133800c5d3f6bd0bda46e5fff8a9897ad27c76bc3d630f8e7c1f347bc23
004d6678b6d0362214f10b39fd3a9810ee776889f13431e7463f7f9635a3134d
5ee9b85ea52bf241bb9b6dbe1756e18b19121e7a7ccdc19103f532fadd146372
6fc835eaeb3d5c2b845ea7f39613259582967f7f9db6cd09842e4c23b5db986d
6fc46495885d7092c931f35b5d6e94e80ac9f7e53694532f037dd5e0b534229c
7a54020a4ea6bf968e9f288a2a27f67cc542015e322318c1dd1f192b4ed0c985
7b54643e298e1ba64abca17da71b6c6f62aeb0093d1054790ee572e2c546e816
7e40024a2f1235828be993b90a56041591c013b1d7766aa812f51b0a7a8690bd
7eaad15a2cf8fa8cc5ce022340a502c3999029300fda9c77e0e7e92c23ed6f35
7f51ee5b896ca7f2212d6833cf0f31b3f6302970e59ed8af815c27ddf8e08993
7f73fce4501912dd079a2fccf7f5f1179beec0e18ed413f61d1217a9b085f591
8c68adb9648f4394fff94475267717aebbe9d2eb0f410bd25d3e0cd5bd39d864
9cc1f0bb057c11016929015d737de5cb0f362afb8fb0dccbd3296adde94db5d6
9e354d8249d4979b14cfc33e7eeeb722ca40b5484cb71c9ea20fd8619b26fc14
19cb50f9b404305532eb17d813d85a4f3c30536fe003bae0578b24522b958aa6
28b9b2e2ab0f65ea6f4f14d1b46d7e99d974996c98fe6d1fe65539531de5fed6
28eebeb04c8ffbc3287bfbbc12bacf66696e2cb9a6fbbd56d6856ec0bb0791bb
33a87ebb45c1978d79facb7f40a994d7e3302e794785f4a23707ffed8c45e5c7
36fc7342cfc14725cfea88dcab20fcd372902ef0f374e7b7708e3bf7c5014edb
44db774b08e78a055f628bb3c39c6a02be721aee5c48a640d02864d4d7f5f0bb
47d221b053a55d65147857bce0bce82cfbbea54237d8971bb172be3524659b53
49e03c2f2316bc8638f1353a44c839d547c43d5ba13395bec200af94d1407263
56d0b6a5e74a0167d109b2587ac622a0d542bb54cf8ed32ebc6f33c0fe831ab2
70babfd252ca5c26d6ec0fe4eaf2136a1c2ab2f0a97c669af9cc54748408855b
84b3cdd6d5f4cebc7fb671fab13e542c5d32f997062922c49067e628fa91ce21
090bd2be79fd4913bf7e5c8c3d7f0f506e511674333c1ebaab4bf917c42f69b6
90e1aedda2853f52f9ccfea587d50fbb58fc546645b3b630fb176a56c617c8cd
91d0aba9e25a5bf7528a6e89fa55bb05d1d2a4d08aa51ac021a50f6981e40478
110edc742a2818c7f4aa430e1780076d0389b7c807d24fafb73299f33e72a7f4
329ddf54f8fb283dcaa09ca41cdad7d449e8a31915c532a0691e5add85d44142
753cb71ecf7b004f80315000a715496574e33934b9f49f39dde3509e0bcda344
777b2eeaacd0be03b7942bbd2ec541aa92d76adeb2959904008bba81a6f7351e
3182fe9e4e773b7248ad9434416f909bdc4dfb41b0063c2ca2198ee80d4b54ec
3608fb1dd92f779d7ea99012cd87756b8b88c67e30db3a4d29443304a055f5cc
5308be170b78d571b9ae2ff9368e281a5421170f88dcc9e83867ee6446c16ce4
7569b99296da7ea2328065cbacb12c39fd65cbf4ba897ab078c573d998c4c470
7855fbd83a74c47cec61e240336b47d23b96ab433a4c43f0710d6fd2964b68b3
9159dd487a0a40c9fd27d3bed76a1f5e26da1547f76fbc185000606e6abf9c9e
18253c1258e34281e8afc45e3349d8b5917bb74427fd48f1ac8737075e55b59e
21046d7445f7d568318d6a310c25d65b7f8942b1e5cdec5f399b956884690f10
27060a661b2dea93dc1ce72b887fc622a4d4573c6a532142152be9374467cf5e
59793aef786ddcd3e374a9eed48bb08d46841fcc6f5e4b76452fc0561ac6f3ec
439752f9774aa9765c71a7ee1e662a420048c66a0c595f06c672ea836905897a
7293511ea98b74247a275d1d31121ec31c2a5144eb748dfc4495dbbf3614e3a5
37357541d22c185047a053304a3a49e6137fadc6ca7eb24e2575b4238e9505fc
390889452b24af8349f770ec97f209b89abdeae06e6c1211fce16e80a4b9d261
a0d88516307b4331756a12b3f088eb373589c753993ebb7063ce4cbba564620c
a590ea71f3cfb8faa9cb399b687a1082095194fd3daa51a52af540a9098c348b
a47271a87450a41b3db59f7fe4cdb453e501762452709cb69cf1a850d5c6317e
a85065533611284f372ba73640162face5303fe1fbe6dbcb74570ea43b7c342c
aaefd3e30806757fe9348ba99a398e11ca5e06ca39587e84a36d06eb848d4f31
ab448b8a09a7ea0cfbc78bd7d61f815ce4f43ae6d2a748d926fb7e78d8541473
abb5a50b08b1c2fc1111bd4b375be65d9d1275233196e6c39f0c9122b8fb1c8b
b8d31f1dd57d0cf2ac69445db4e899c2353ce7ba59fe2942bc0d5c0b9b83d494
b9b8a45d6fdc5358fefcdcfe632a1a23429e3bc8e39f8c55e12ecda4865dbe0a
bc5e9da0574d6e3e079d716009c10c72b980af2816332fdc79925ed100e29295
bedcb5614ecec48607977707635affd47d4cc7ce4d5423126eeb95a80241dcb4
c6a423c972bc8d5e60c0298b2cb6ff0ee2e31d2191e8aa3c7ae296ce1c50e0cd
c12c716773c7b2adb42c626edff1faeb99034790580f076d4467cfcd54779e84
cd19f24203d3084203402793b5865d355293f5f0ae1046eaf7cbabe389698160
cd992fb590ea3a34185183d9f461c698e1d694288828ec65520d1307e086445a
cfeb838043841df1925a44a2c2b65e36f5ecf6e39698291120b750720d0a0558
d8d80f8ebe915d25712f2c34ef3512ff2b93e29080899cc66973dd27e02dd986
dd96daf7fc7b868235b4b6d9f279b913cc98c7793149cef31b5e7cef9927cc9b
e1f4e36d634e987742cb407fc00255569ea67721e28de07ff285d75ed4f87597
e6f774ee7ee671c13e24f1080950e5362ba833c1e3ce2ee0f872d2f2e68a2147
e18e0122a933d529be6ab89070cfd70a800fef2edc5ca3db921d1cfb9fa3cac6
e65cb0cadc96854ae9eaceeb95d8147aad58851c02b78bb6ec18c96fb3d50557
ea094604b6d4c1b230a0248a46b87d59b76b05e9c1e52587c68ac51809f0487b
f0cc746de37835a8f475f9b2d9dab24654f294568ce70431c35df021aafbfe30
f7f91c9e6d6fccd454f411b0a11c14d2cc9f281b27e2bf2ebc4773e5f1c44f7f
f20f264822d41330e345e8623b5343f8c6952a63fc40610a7b6ba836f7848066
f708566975292176cecbdc992bba43a4470fe389fa07b4a4d92949117aecb0a1
fdff11a8fcc218f7f4bed44069a64a35704e1f49066eac82580dc476ef2d4d24
ff4c51635a39989c431c4e4343054c60ded58f251d137264040abf29facfe257
ffe23faaddfece1e41310ac88b8027dab3594a2cac3088d79d4b12347fb850f7

Empty file.

0 comments on commit 0fce4e0

Please sign in to comment.