<commit_before>require "phoenix_password/version"

class PhoenixPassword
	def self.generate_combinations(data)
		characters=data[:characters]
		if !data[:extra_chars].nil?
			characters.push(data[:extra_chars][data[:iteration]-1])  if data[:iteration] != 0
		end
		combination=Array.new(data[:cmb_length],data[:characters].first)
		combination_length=combination.length
		i=0
		possible_combinations=characters.length**combination_length
		chars_used=Array.new(data[:cmb_length],0)
		
		while i < possible_combinations
			x=1
			change_count=1
			while x < combination_length
				if chars_used[x] == characters.length
					chars_used[x] = 0
				end
				if combination[x] == characters.last && combination[x+1] == characters.last
					change_count +=1
					if change_count == combination_length -1
						chars_used[0] += 1
					end
				end
				x +=1
			end

			y=0
			until y == combination_length
				combination[y]=characters[chars_used[y]]
				y+=1
			end

			if data[:extra_chars].nil? || data[:iteration] == 0
				yield(combination.join())
			else
 			  yield(combination.join()) if combination.include?(characters.last)
			end

			z=combination_length-1
			while 1 < z
				if  z == combination_length-1
					chars_used[z-1] +=1	if combination[z] == characters.last 
				else
					diff=(combination_length-1)-z
					last_chars=0
					count_diff=1
					while count_diff <= diff
						if combination[z] == characters.last && combination[z+count_diff] == characters.last
							last_chars +=1
						end
						count_diff +=1
					end
					if last_chars == (combination_length-1)-z
						chars_used[z-1] +=1
					end
				end
				z-=1
			end
			chars_used[combination_length-1] +=1
			i+=1
		end
		return characters
	end
	
	def self.matching_combinations(info)
		data={:characters=>info[:characters],:cmb_length=>info[:cmb_length],:type=>info[:type]}
	    unless info[:extra_chars].nil?
	   	 	 data[:extra_chars]=info[:extra_chars]
	    end

		matching_file=create_file(info) if !info[:piped]

		char_sum=data[:characters].length
		total_characters=data[:characters].length
		unless data[:extra_chars].nil?
			total_characters=data[:characters].length+data[:extra_chars].length
			data[:iteration]=0
			if info[:skip_first] || !info[:piped]
				data[:iteration] +=1
				char_sum +=1
			end
		end
		
		matching=0
		begin
			generate_combinations(data) do |combination;i|
				if matching_check({:combination=>combination,:match_limit=>info[:match_limit]})
					if info[:piped]
						puts combination
					elsif !matching_file.nil?
						if data[:extra_chars].nil?
							matching_file.puts(combination)
						elsif data[:iteration] >= 1
							matching_file.puts(combination)
						end
					end
					matching +=1
				end
			end
			data[:iteration]+=1 unless data[:iteration].nil?
			char_sum +=1
		rescue => e
			raise
	    end while char_sum <= total_characters
		matching_file.close unless matching_file.nil?
		return matching
	end

	def self.matching_check(info)
		combination=info[:combination]
		i=0
		x=0
		u=0
		while i < (combination.length-1)
			if combination[i] == combination[i+1]
  	 	      return true if info[:match_limit].nil?
		 	  if i == 0
		 	     x +=1
		 	  elsif combination[i] == combination[i-1] 	|| combination[i] == combination[i+info[:match_limit]] 
		 	  	 x+=1		 	  			
		 	  end
		 	else 
		 		u +=1
			end
		    if x == info[:match_limit] || u == combination.length-1
			 return false
		    end
			i+=1
		end
		return true
	end

	def self.unique_combinations(info)	 
	   data={:characters=>info[:characters],:cmb_length=>info[:cmb_length],:type=>info[:type]}
	   unless info[:extra_chars].nil?
	   		data[:extra_chars]=info[:extra_chars]
	   end

 	   unique_file=create_file(info) unless info[:piped]

	   total_characters=data[:characters].length
	   char_sum= data[:characters].length
	   unless data[:extra_chars].nil?
			total_characters=data[:characters].length+data[:extra_chars].length
			data[:iteration]=0
			if info[:skip_first] || !info[:piped]
				data[:iteration]+=1
				char_sum +=1
			end
	   end
	   unique_combs=0
	   uniqueness=info[:uniqueness_type]
	   begin
			generate_combinations(data) do |combination|
				unique_chars=check_uniqueness(combination,uniqueness)
				if unique_chars == combination.length-1
					puts combination if info[:piped]
					unless unique_file.nil?
					  unless data[:extra_chars].nil?
					  	if data[:iteration] != 0
					  	  unique_file.puts(combination)
					  	end
					  else	
						 unique_file.puts(combination)
					  end
					end
					unique_combs= unique_combs+1
				end
			end
			data[:iteration] +=1 if !data[:iteration].nil?
			char_sum +=1
		rescue => e
			raise
		end while char_sum <= total_characters
		
		unless unique_file.nil?
			unique_file.close
		end

		return unique_combs
	end

	def self.check_uniqueness(combination,uniqueness)
		i=0
		unique_chars=0
		chars_check=[]
		while i < (combination.length-1)
			if combination[i] != combination[i+1]
			  if uniqueness.nil?
			     unique_chars+=1
			  elsif uniqueness == "single"<commit_msg>Reduced combination generation time<commit_after>require "phoenix_password/version"

class PhoenixPassword
	def self.generate_combinations(data)
		characters=data[:characters]
		if !data[:extra_chars].nil?
			characters.push(data[:extra_chars][data[:iteration]-1])  if data[:iteration] != 0
		end
		combination=Array.new(data[:cmb_length],data[:characters].first)
		combination_length=combination.length
		i=0
		possible_combinations=characters.length**combination_length
		chars_used=Array.new(data[:cmb_length],0)
		
		while i < possible_combinations/characters.length
			x=1
			change_count=1
			while x < combination_length
				if chars_used[x] == characters.length
					chars_used[x] = 0
				end
				if combination[x] == characters.last && combination[x+1] == characters.last
					change_count +=1
					if change_count == combination_length -1
						chars_used[0] += 1
					end
				end
				x +=1
			end

			y=0
			until y == combination_length
				combination[y]=characters[chars_used[y]]
				y+=1
			end

			if data[:extra_chars].nil? || data[:iteration] == 0
				combinations=[]
				combinations.<<(combination.join())
				if combination.last != characters.first
					reverse_comb=combination.reverse
					combinations.<<(reverse_comb.join())
					reverse_comb.pop
					reverse_comb=reverse_comb.join()
					characters.each do |char|
						next if char == characters.first
						combinations.<<("%s%s"%[reverse_comb,char])
					end
				end
				yield(combinations)
			else
 			  yield(combination.join()) if combination.include?(characters.last)
			end

			z=combination_length-1
			while 1 < z
				if  z == combination_length-1
					chars_used[z-1] +=1	if combination[z] == characters.last 
				else
					diff=(combination_length-1)-z
					last_chars=0
					count_diff=1
					while count_diff <= diff
						if combination[z] == characters.last && combination[z+count_diff] == characters.last
							last_chars +=1
						end
						count_diff +=1
					end
					if last_chars == (combination_length-1)-z
						chars_used[z-1] +=1
					end
				end
				z-=1
			end
			chars_used[combination_length-1] +=1
			i+=1
		end
		return characters
	end
	
	def self.matching_combinations(info)
		data={:characters=>info[:characters],:cmb_length=>info[:cmb_length],:type=>info[:type]}
	    unless info[:extra_chars].nil?
	   	 	 data[:extra_chars]=info[:extra_chars]
	    end

		matching_file=create_file(info) if !info[:piped]

		char_sum=data[:characters].length
		total_characters=data[:characters].length
		unless data[:extra_chars].nil?
			total_characters=data[:characters].length+data[:extra_chars].length
			data[:iteration]=0
			if info[:skip_first] || !info[:piped]
				data[:iteration] +=1
				char_sum +=1
			end
		end
		
		matching=0
		begin
		 generate_combinations(data) do |combinations|
		  combinations.each do |combination|
			if matching_check({:combination=>combination,:match_limit=>info[:match_limit]})
			 if info[:piped]
					puts combination
			 elsif !matching_file.nil?
			 	if data[:extra_chars].nil?
						matching_file.puts(combination)
				elsif data[:iteration] >= 1
					matching_file.puts(combination)
				end
			 end
			 matching +=1
			end
		  end
		 end
			data[:iteration]+=1 unless data[:iteration].nil?
			char_sum +=1
		rescue => e
			raise
	    end while char_sum <= total_characters
		matching_file.close unless matching_file.nil?
		return matching
	end

	def self.matching_check(info)
		combination=info[:combination]
		i=0
		x=0
		u=0
		while i < (combination.length-1)
			if combination[i] == combination[i+1]
  	 	      return true if info[:match_limit].nil?
		 	  if i == 0
		 	     x +=1
		 	  elsif combination[i] == combination[i-1] 	|| combination[i] == combination[i+info[:match_limit]] 
		 	  	 x+=1		 	  			
		 	  end
		 	else 
		 		u +=1
			end
		    if x == info[:match_limit] || u == combination.length-1
			 return false
		    end
			i+=1
		end
		return true
	end

	def self.unique_combinations(info)	 
	   data={:characters=>info[:characters],:cmb_length=>info[:cmb_length],:type=>info[:type]}
	   unless info[:extra_chars].nil?
	   		data[:extra_chars]=info[:extra_chars]
	   end

 	   unique_file=create_file(info) unless info[:piped]

	   total_characters=data[:characters].length
	   char_sum= data[:characters].length
	   unless data[:extra_chars].nil?
			total_characters=data[:characters].length+data[:extra_chars].length
			data[:iteration]=0
			if info[:skip_first] || !info[:piped]
				data[:iteration]+=1
				char_sum +=1
			end
	   end
	   unique_combs=0
	   uniqueness=info[:uniqueness_type]
	   begin
		generate_combinations(data) do |combinations|
		  combinations.each do |combination|
			 unique_chars=check_uniqueness(combination,uniqueness)
		 	 if unique_chars == combination.length-1
				puts combination if info[:piped]
			  	 unless unique_file.nil?
				   unless data[:extra_chars].nil?
				   	if data[:iteration] != 0
				   	  unique_file.puts(combination)
				  	end
				  else	
					 unique_file.puts(combination)
				  end
			 end
			 unique_combs= unique_combs+1
		   end
		  end
		end
		data[:iteration] +=1 if !data[:iteration].nil?
		char_sum +=1
		rescue => e
			raise
		end while char_sum <= total_characters
		
		unless unique_file.nil?
			unique_file.close
		end

		return unique_combs
	end

	def self.check_uniqueness(combination,uniqueness)
		i=0
		unique_chars=0
		chars_check=[]
		while i < (combination.length-1)
			if combination[i] != combination[i+1]
			  if uniqueness.nil?
			     unique_chars+=1
			  elsif uniqueness == "single"
{'fraction_non_alphanumeric': 0.1181310886219616, 'fraction_numerical': 0.012673791733661212, 'mean_word_length': 3.3694214876033057, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2847489', 'n_tokens_mistral': 4529, 'n_tokens_neox': 3549, 'n_words': 671}