

'''simple docstring'''







import logging
import math
from functools import partial
from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple, Union

import torch

from .tensor_utils import tensor_tree_map, tree_map
def    UpperCAmelCase__     (   UpperCAmelCase__					)      ->      List[Tuple[int, ...]]:
       A_						       =   []
       if isinstance(UpperCAmelCase__,							UpperCAmelCase__					):
              for v in tree.values():
                     shapes.extend(_fetch_dims(UpperCAmelCase__					)					)
       elif isinstance(UpperCAmelCase__,							(list, tuple)					):
              for t in tree:
                     shapes.extend(_fetch_dims(UpperCAmelCase__					)					)
       elif isinstance(UpperCAmelCase__,							torch.Tensor					):
              shapes.append(tree.shape					)
       else:
              raise ValueError("""Not supported"""					)

       return shapes
@torch.jit.ignore
def    UpperCAmelCase__     (   UpperCAmelCase__,							UpperCAmelCase__					)      ->      Tuple[int, ...]:
       A_						       =   []
       for d in reversed(UpperCAmelCase__					):
              idx.append(flat_idx % d					)
              A_						       =   flat_idx // d

       return tuple(reversed(UpperCAmelCase__					)					)
@torch.jit.ignore
def    UpperCAmelCase__     (   UpperCAmelCase__,							UpperCAmelCase__,							UpperCAmelCase__,							UpperCAmelCase__ = None,							UpperCAmelCase__ = None,							)      ->      List[Tuple[slice, ...]]:

       # start_edges and end_edges both indicate whether, starting from any given
       # dimension, the start/end index is at the top/bottom edge of the
       # corresponding tensor, modeled as a tree
       def reduce_edge_list(UpperCAmelCase__					) -> None:
              A_						       =   True
              for i in range(len(UpperCAmelCase__					)					):
                     A_						       =   -1 * (i + 1)
                     l[reversed_idx] &= tally
                     A_						       =   l[reversed_idx]

       if start_edges is None:
              A_						       =   [s == 0 for s in start]
              reduce_edge_list(UpperCAmelCase__					)
       if end_edges is None:
              A_						       =   [e == (d - 1) for e, d in zip(UpperCAmelCase__,							UpperCAmelCase__					)]
              reduce_edge_list(UpperCAmelCase__					)

       # Base cases. Either start/end are empty and we're done, or the final,
       # one-dimensional tensor can be simply sliced
       if len(UpperCAmelCase__					) == 0:
              return [()]
       elif len(UpperCAmelCase__					) == 1:
              return [(slice(start[0],							end[0] + 1					),)]

       A_						       =   []
       A_						       =   []

       # Dimensions common to start and end can be selected directly
       for s, e in zip(UpperCAmelCase__,							UpperCAmelCase__					):
              if s == e:
                     path_list.append(slice(UpperCAmelCase__,							s + 1					)					)
              else:
                     break

       A_						       =   tuple(UpperCAmelCase__					)
       A_						       =   len(UpperCAmelCase__					)

       # start == end, and we're done
       if divergence_idx == len(UpperCAmelCase__					):
              return [path]

       def upper() -> Tuple[Tuple[slice, ...], ...]:
              assert start_edges is not None
              assert end_edges is not None

              A_						       =   start[divergence_idx]
              return tuple(
                  path + (slice(UpperCAmelCase__,							sdi + 1					),) + s
                  for s in _get_minimal_slice_set(
                      start[divergence_idx + 1 :],							[d - 1 for d in dims[divergence_idx + 1 :]],							dims[divergence_idx + 1 :],							start_edges=start_edges[divergence_idx + 1 :],							end_edges=[True for _ in end_edges[divergence_idx + 1 :]],							)					)

       def lower() -> Tuple[Tuple[slice, ...], ...]:
              assert start_edges is not None
              assert end_edges is not None

              A_						       =   end[divergence_idx]
              return tuple(
                  path + (slice(UpperCAmelCase__,							edi + 1					),) + s
                  for s in _get_minimal_slice_set(
                      [0 for _ in start[divergence_idx + 1 :]],							end[divergence_idx + 1 :],							dims[divergence_idx + 1 :],							start_edges=[True for _ in start_edges[divergence_idx + 1 :]],							end_edges=end_edges[divergence_idx + 1 :],							)					)

       # If both start and end are at the edges of the subtree rooted at
       # divergence_idx, we can just select the whole subtree at once
       if start_edges[divergence_idx] and end_edges[divergence_idx]:
              slices.append(path + (slice(start[divergence_idx],							end[divergence_idx] + 1					),)					)
       # If just start is at the edge, we can grab almost all of the subtree,
       # treating only the ragged bottom edge as an edge case
       elif start_edges[divergence_idx]:
              slices.append(path + (slice(start[divergence_idx],							end[divergence_idx]					),)					)
              slices.extend(lower()					)
       # Analogous to the previous case, but the top is ragged this time
       elif end_edges[divergence_idx]:
              slices.extend(upper()					)
              slices.append(path + (slice(start[divergence_idx] + 1,							end[divergence_idx] + 1					),)					)
       # If both sides of the range are ragged, we need to handle both sides
       # separately. If there's contiguous meat in between them, we can index it
       # in one big chunk
       else:
              slices.extend(upper()					)
              A_						       =   end[divergence_idx] - start[divergence_idx]
              if middle_ground > 1:
                     slices.append(path + (slice(start[divergence_idx] + 1,							end[divergence_idx]					),)					)
              slices.extend(lower()					)

       return slices
@torch.jit.ignore
def    UpperCAmelCase__     (   UpperCAmelCase__,							UpperCAmelCase__,							UpperCAmelCase__,							UpperCAmelCase__					)      ->      torch.Tensor:
       A_						       =   t.shape[:no_batch_dims]
       A_						       =   list(_flat_idx_to_idx(UpperCAmelCase__,							UpperCAmelCase__					)					)
       # _get_minimal_slice_set is inclusive
       A_						       =   list(_flat_idx_to_idx(flat_end - 1,							UpperCAmelCase__					)					)

       # Get an ordered list of slices to perform
       A_						       =   _get_minimal_slice_set(
           UpperCAmelCase__,							UpperCAmelCase__,							UpperCAmelCase__,							)

       A_						       =   [t[s] for s in slices]

       return torch.cat([s.view((-1,) + t.shape[no_batch_dims:]					) for s in sliced_tensors]					)
def    UpperCAmelCase__     (   UpperCAmelCase__,							UpperCAmelCase__,							UpperCAmelCase__,							UpperCAmelCase__,							UpperCAmelCase__ = False,							UpperCAmelCase__ = None,							UpperCAmelCase__ = False,							)      ->      Any:
       if not (len(UpperCAmelCase__					) > 0):
              raise ValueError("""Must provide at least one input"""					)

       A_						       =   [shape[:no_batch_dims] for shape in _fetch_dims(UpperCAmelCase__					)]
       A_						       =   tuple([max(UpperCAmelCase__					) for s in zip(*UpperCAmelCase__					)]					)

       def _prep_inputs(UpperCAmelCase__					) -> torch.Tensor:
              if not low_mem:
                     if not sum(t.shape[:no_batch_dims]					) == no_batch_dims:
                            A_						       =   t.expand(orig_batch_dims + t.shape[no_batch_dims:]					)
                     A_						       =   t.reshape(-1,							*t.shape[no_batch_dims:]					)
              else:
                     A_						       =   t.expand(orig_batch_dims + t.shape[no_batch_dims:]					)
              return t

       A_						       =   tensor_tree_map(_prep_inputs,							UpperCAmelCase__					)
       A_						       =   None
       if _out is not None:
              A_						       =   tensor_tree_map(lambda UpperCAmelCase__					: t.view([-1] + list(t.shape[no_batch_dims:]					)					),							_out					)

       A_						       =   1
       for d in orig_batch_dims:
              flat_batch_dim *= d

       A_						       =   flat_batch_dim // chunk_size + (flat_batch_dim % chunk_size != 0)

       def _select_chunk(UpperCAmelCase__					) -> torch.Tensor:
              return t[i : i + chunk_size] if t.shape[0] != 1 else t

       A_						       =   0
       A_						       =   prepped_outputs
       for _ in range(UpperCAmelCase__					):
              # Chunk the input
              if not low_mem:
                     A_						       =   _select_chunk
              else:
                     A_						       =   partial(
                         _chunk_slice,							flat_start=UpperCAmelCase__,							flat_end=min(UpperCAmelCase__,							i + chunk_size					),							no_batch_dims=len(UpperCAmelCase__					),							)

              A_						       =   tensor_tree_map(UpperCAmelCase__,							UpperCAmelCase__					)

              # Run the layer on the chunk
              A_						       =   layer(**UpperCAmelCase__					)

              # Allocate space for the output
              if out is None:
                     A_						       =   tensor_tree_map(lambda UpperCAmelCase__					: t.new_zeros((flat_batch_dim,) + t.shape[1:]					),							UpperCAmelCase__					)

              # Put the chunk in its pre-allocated space
              if isinstance(UpperCAmelCase__,							UpperCAmelCase__					):

                     def assign(UpperCAmelCase__,							UpperCAmelCase__					) -> None:
                            for k, v in da.items():
                                   if isinstance(UpperCAmelCase__,							UpperCAmelCase__					):
                                          assign(UpperCAmelCase__,							da[k]					)
                                   else:
                                          if _add_into_out:
                                                 v[i : i + chunk_size] += da[k]
                                          else:
                                                 A_						       =   da[k]

                     assign(UpperCAmelCase__,							UpperCAmelCase__					)
              elif isinstance(UpperCAmelCase__,							UpperCAmelCase__					):
                     for xa, xa in zip(UpperCAmelCase__,							UpperCAmelCase__					):
                            if _add_into_out:
                                   xa[i : i + chunk_size] += xa
                            else:
                                   A_						       =   xa
              elif isinstance(UpperCAmelCase__,							torch.Tensor					):
                     if _add_into_out:
                            out[i : i + chunk_size] += output_chunk
                     else:
                            A_						       =   output_chunk
              else:
                     raise ValueError("""Not supported"""					)

              i += chunk_size

       A_						       =   tensor_tree_map(lambda UpperCAmelCase__					: t.view(orig_batch_dims + t.shape[1:]					),							UpperCAmelCase__					)

       return out







class        A__   :



    def __init__(       self		,					UpperCamelCase__ = 512		,					)    ->   Dict:





           '''simple docstring'''
           A_						       =   max_chunk_size
           A_						       =   None
           A_						       =   None



    def        snake_case_      (       self		,					UpperCamelCase__		,					UpperCamelCase__		,					UpperCamelCase__							)    ->   int:





           '''simple docstring'''
           logging.info("""Tuning chunk size..."""							)

           if min_chunk_size >= self.max_chunk_size:
                  return min_chunk_size

           A_						       =   [2**l for l in range(int(math.log(self.max_chunk_size		,					2							)							) + 1							)]
           A_						       =   [c for c in candidates if c > min_chunk_size]
           A_						       =   [min_chunk_size] + candidates
           candidates[-1] += 4

           def test_chunk_size(UpperCamelCase__							) -> bool:
                  try:
                         with torch.no_grad():
                                fn(*UpperCamelCase__		,					chunk_size=UpperCamelCase__							)
                         return True
                  except RuntimeError:
                         return False

           A_						       =   0
           A_						       =   len(UpperCamelCase__							) - 1
           while i > min_viable_chunk_size_index:
                  A_						       =   test_chunk_size(candidates[i]							)
                  if not viable:
                         A_						       =   (min_viable_chunk_size_index + i) // 2
                  else:
                         A_						       =   i
                         A_						       =   (i + len(UpperCamelCase__							) - 1) // 2

           return candidates[min_viable_chunk_size_index]



    def        snake_case_      (       self		,					UpperCamelCase__		,					UpperCamelCase__							)    ->   bool:





           '''simple docstring'''
           A_						       =   True
           for aa, aa in zip(UpperCamelCase__		,					UpperCamelCase__							):
                  assert type(UpperCamelCase__							) == type(UpperCamelCase__							)
                  if isinstance(UpperCamelCase__		,					(list, tuple)							):
                         consistent &= self._compare_arg_caches(UpperCamelCase__		,					UpperCamelCase__							)
                  elif isinstance(UpperCamelCase__		,					UpperCamelCase__							):
                         A_						       =   [v for _, v in sorted(aa.items()		,					key=lambda UpperCamelCase__							: x[0]							)]
                         A_						       =   [v for _, v in sorted(aa.items()		,					key=lambda UpperCamelCase__							: x[0]							)]
                         consistent &= self._compare_arg_caches(UpperCamelCase__		,					UpperCamelCase__							)
                  else:
                         consistent &= aa == aa

           return consistent







    def        snake_case_      (       self		,					UpperCamelCase__		,					UpperCamelCase__		,					UpperCamelCase__		,					)    ->   int:





           '''simple docstring'''
           A_						       =   True
           A_						       =   tree_map(lambda UpperCamelCase__							: a.shape if isinstance(UpperCamelCase__		,					torch.Tensor							) else a		,					UpperCamelCase__		,					UpperCamelCase__							)
           if self.cached_arg_data is not None:
                  # If args have changed shape/value, we need to re-tune
                  assert len(self.cached_arg_data							) == len(UpperCamelCase__							)
                  A_						       =   self._compare_arg_caches(self.cached_arg_data		,					UpperCamelCase__							)
           else:
                  # Otherwise, we can reuse the precomputed value
                  A_						       =   False

           if not consistent:
                  A_						       =   self._determine_favorable_chunk_size(
                      UpperCamelCase__		,					UpperCamelCase__		,					UpperCamelCase__		,					)
                  A_						       =   arg_data

           assert self.cached_chunk_size is not None

           return self.cached_chunk_size



'''simple docstring'''







import csv

import tweepy

# Twitter API credentials
__lowerCamelCase									=     ''''''
__lowerCamelCase									=     ''''''
__lowerCamelCase									=     ''''''
__lowerCamelCase									=     ''''''
def    UpperCAmelCase__     (   UpperCAmelCase__					)      ->      None:
       # authorize twitter, initialize tweepy
       A_						       =   tweepy.OAuthHandler(UpperCAmelCase__,							UpperCAmelCase__					)
       auth.set_access_token(UpperCAmelCase__,							UpperCAmelCase__					)
       A_						       =   tweepy.API(UpperCAmelCase__					)

       # initialize a list to hold all the tweepy Tweets
       A_						       =   []

       # make initial request for most recent tweets (200 is the maximum allowed count)
       A_						       =   api.user_timeline(screen_name=UpperCAmelCase__,							count=2_00					)

       # save most recent tweets
       alltweets.extend(UpperCAmelCase__					)

       # save the id of the oldest tweet less one
       A_						       =   alltweets[-1].id - 1

       # keep grabbing tweets until there are no tweets left to grab
       while len(UpperCAmelCase__					) > 0:
              print(F'''getting tweets before {oldest}'''					)

              # all subsequent requests use the max_id param to prevent duplicates
              A_						       =   api.user_timeline(
                  screen_name=UpperCAmelCase__,							count=2_00,							max_id=UpperCAmelCase__					)

              # save most recent tweets
              alltweets.extend(UpperCAmelCase__					)

              # update the id of the oldest tweet less one
              A_						       =   alltweets[-1].id - 1

              print(F'''...{len(UpperCAmelCase__					)} tweets downloaded so far'''					)

       # transform the tweepy tweets into a 2D array that will populate the csv
       A_						       =   [[tweet.id_str, tweet.created_at, tweet.text] for tweet in alltweets]

       # write the csv
       with open(F'''new_{screen_name}_tweets.csv''',							"""w"""					) as f:
              A_						       =   csv.writer(UpperCAmelCase__					)
              writer.writerow(["""id""", """created_at""", """text"""]					)
              writer.writerows(UpperCAmelCase__					)


if __name__ == "__main__":
      # pass in the username of the account you want to download
      get_all_tweets('''FirePing32''')
