diff --git a/.circleci/config.yml b/.circleci/config.yml
index 4ae3eb9a..20edc98f 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -17,6 +17,7 @@ jobs:
name: Run Tests
command: |
make test
+ no_output_timeout: 30m
- store_test_results:
path: /home/circleci/project/tests/test-reports
- store_artifacts:
diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
index 38af1c27..9df6ca8b 100644
--- a/.github/ISSUE_TEMPLATE/bug-report.md
+++ b/.github/ISSUE_TEMPLATE/bug-report.md
@@ -3,7 +3,7 @@ name: Bug report
about: Provide the details of the bug to us in order to further triage and fix
title: "[BUG]"
labels: bug
-assignees: li-wu, GordonWang
+assignees: lephino, arctan5x, jmeixensperger, li-wu, GordonWang
---
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index 30a5b6f2..046874e8 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -3,7 +3,7 @@ name: Feature request
about: Suggest an idea or improvement for this project
title: "[FEATURE/IMPROVEMENT]"
labels: enhancement
-assignees: li-wu, GordonWang
+assignees: lephino, arctan5x, jmeixensperger, li-wu, GordonWang
---
diff --git a/.gitignore b/.gitignore
index 228e620a..d0e9c0ba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,7 +17,6 @@ stage/
local/
eventgen_wsgi.conf
*.log
-dist
*.egg-info
**/*.tgz
.cache
@@ -27,3 +26,4 @@ _book
*.result
venv/*
*.log.*
+splunk_eventgen-*/
diff --git a/.yapfignore b/.yapfignore
new file mode 100644
index 00000000..85fef0c5
--- /dev/null
+++ b/.yapfignore
@@ -0,0 +1,2 @@
+splunk_eventgen/lib/concurrent
+splunk_eventgen/lib/requests_futures
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 38ab06bd..f418bcb2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,99 +1,16 @@
# Contributing
-When contributing to this repository, please first discuss the change you wish to make via issue,
-email, or any other method with the owners of this repository before making a change.
+When contributing to this repository, please read over the [contributing document](http://splunk.github.io/eventgen/CONTRIBUTE.html). [Create a issue](http://splunk.github.io/eventgen/FILE_ISSUES.html) to discuss your demand and follow the [guidelines](http://splunk.github.io/eventgen/CONTRIBUTE_CODE.html) to make the code change
-Please note we have a code of conduct, please follow it in all your interactions with the project.
+Please note we have a [code of conduct](http://splunk.github.io/eventgen/CONTRIBUTE.html#code-of-conduct), please follow it in all your interactions with the project.
-## Pull Request Process
-
-1. Ensure any install or build dependencies are removed before the end of the layer when doing a
- build.
-2. Update the splunk_eventgen/README/eventgen.conf.spec with details of changes to the interface, this includes new environment
- variables, exposed ports, useful file locations and container parameters. Also, update the necessary documentation.
-3. Increase the version numbers in splunk_eventgen/version.json. The versioning scheme we use is [SemVer](http://semver.org/).
-4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
- do not have permission to do that, you may request the second reviewer to merge it for you.
-
-## Code of Conduct
-
-### Our Pledge
-
-In the interest of fostering an open and welcoming environment, we as
-contributors and maintainers pledge to making participation in our project and
-our community a harassment-free experience for everyone, regardless of age, body
-size, disability, ethnicity, gender identity and expression, level of experience,
-nationality, personal appearance, race, religion, or sexual identity and
-orientation.
-
-### Our Standards
-
-Examples of behavior that contributes to creating a positive environment
-include:
-
-* Using welcoming and inclusive language
-* Being respectful of differing viewpoints and experiences
-* Gracefully accepting constructive criticism
-* Focusing on what is best for the community
-* Showing empathy towards other community members
-
-Examples of unacceptable behavior by participants include:
-
-* The use of sexualized language or imagery and unwelcome sexual attention or
-advances
-* Trolling, insulting/derogatory comments, and personal or political attacks
-* Public or private harassment
-* Publishing others' private information, such as a physical or electronic
- address, without explicit permission
-* Other conduct which could reasonably be considered inappropriate in a
- professional setting
-
-### Our Responsibilities
-
-Project maintainers are responsible for clarifying the standards of acceptable
-behavior and are expected to take appropriate and fair corrective action in
-response to any instances of unacceptable behavior.
-
-Project maintainers have the right and responsibility to remove, edit, or
-reject comments, commits, code, wiki edits, issues, and other contributions
-that are not aligned to this Code of Conduct, or to ban temporarily or
-permanently any contributor for other behaviors that they deem inappropriate,
-threatening, offensive, or harmful.
-
-### Scope
-
-This Code of Conduct applies both within project spaces and in public spaces
-when an individual is representing the project or its community. Examples of
-representing a project or community include using an official project e-mail
-address, posting via an official social media account, or acting as an appointed
-representative at an online or offline event. Representation of a project may be
-further defined and clarified by project maintainers.
-
-### Enforcement
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be
-reported by contacting the project team at tonyl@splunk.com. All
-complaints will be reviewed and investigated and will result in a response that
-is deemed necessary and appropriate to the circumstances. The project team is
-obligated to maintain confidentiality with regard to the reporter of an incident.
-Further details of specific enforcement policies may be posted separately.
-
-Project maintainers who do not follow or enforce the Code of Conduct in good
-faith may face temporary or permanent repercussions as determined by other
-members of the project's leadership.
-
-### Attribution
-
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
-available at [http://contributor-covenant.org/version/1/4][version]
-
-[homepage]: http://contributor-covenant.org
-[version]: http://contributor-covenant.org/version/1/4/
### Past / Active(marked as *) Contributors
bbingham*
arctan5x*
jmeixensperger*
+li-wu*
+GordonWang*
coccyx
Jaykul
allanwsplk
diff --git a/Makefile b/Makefile
index 19969eb9..559bd63b 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ XLARGE ?= 'tests/xlarge'
NEWLY_ADDED_PY_FILES = $(shell git ls-files -o --exclude-standard | grep -E '\.py$$')
CHANGED_ADDED_PY_FILES = $(shell git ls-files -mo --exclude-standard | grep -E '\.py$$')
-.PHONY: tests, lint, format
+.PHONY: tests, lint, format, docs
all: egg
@@ -24,7 +24,7 @@ image: setup_eventgen egg
rm splunk_eventgen/default/eventgen_engine.conf || true
docker build -f dockerfiles/Dockerfile . -t eventgen
-test: egg image test_helper test_collection_cleanup
+test: egg image test_helper run_tests test_collection_cleanup
test_helper:
docker run -d -t --net=host -v /var/run/docker.sock:/var/run/docker.sock --name ${EVENTGEN_TEST_IMAGE} eventgen:latest cat
@@ -41,15 +41,10 @@ test_helper:
@echo 'Installing test requirements'
docker exec -i ${EVENTGEN_TEST_IMAGE} /bin/sh -c "pip install -r $(shell pwd)/tests/requirements.txt" || true
+run_tests:
@echo 'Running the super awesome tests'
docker exec -i ${EVENTGEN_TEST_IMAGE} /bin/sh -c "cd $(shell pwd); python tests/run_tests.py ${SMALL} ${MEDIUM} ${LARGE} ${XLARGE}" || true
- echo 'Collecting results'
- #TODO: Should be paramaterized or generalized so that we don't need to add this here
- docker cp ${EVENTGEN_TEST_IMAGE}:$(shell pwd)/tests_results.xml tests_results.xml || echo "no tests_results.xml" || true
-
- docker stop ${EVENTGEN_TEST_IMAGE} || true
-
test_collection_cleanup:
@echo 'Collecting results'
#TODO: Should be paramaterized or generalized so that we don't need to add this here
@@ -97,9 +92,7 @@ run_controller: eg_network
docker run --name eg_controller --network eg_network -d -p 5672:5672 -p 15672:15672 -p 9500:9500 eventgen:latest controller
docs:
- npm install -g gitbook-serve
- cd docs/
- gitbookserve
+ cd docs/; bundle install; bundle exec jekyll serve
build_spl: clean
python -m splunk_eventgen build --destination ./
@@ -124,3 +117,9 @@ else
@yapf -i $(NEWLY_ADDED_PY_FILES)
endif
+lint-all:
+ @flake8 .
+
+format-all:
+ @isort -rc .
+ @yapf -r -i .
diff --git a/README.md b/README.md
index 06670a58..36080834 100644
--- a/README.md
+++ b/README.md
@@ -33,4 +33,4 @@ The Splunk Event Generator is licensed under the Apache License 2.0. Details can
### Support
This software is released as-is. Splunk provides no warranty and no support on this software.
-If you have any issues with the software, please file an issue (https://github.com/splunk/eventgen/issues/new)
+If you have any issues with the software, please read over the [guidelines](http://splunk.github.io/eventgen/FILE_ISSUES.md) and file an issue.
\ No newline at end of file
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 00000000..ca35be08
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1 @@
+_site
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
index 4c185ab7..bcb926cb 100644
--- a/docs/ARCHITECTURE.md
+++ b/docs/ARCHITECTURE.md
@@ -19,7 +19,7 @@ These requirements have led to this new architecture in verison 4. Eventgen is
* Handles flattening of configs from global defaults and individual config files
* Loading Plugins
* Load plugins from the `lib/plugins` directory or App's `bin` directories, with three types of Plugins: Rating, Generator and Output
- * For more detail on writing plugins, see the [Plugins documentation](Plugins.md)
+ * For more detail on writing plugins, see the [Plugins documentation](PLUGINS.md)
* Creating timers for each sample
* For samples with queueable generators (meaning we can have multiple threads generating sample simultaneously), the timer wakes up every interval and puts a task in the queue to be generated by a generator worker
* For samples which are not queueable (meaning we can only run one simultaneous thread of the generator), the thread runs the generator plugin single threaded and handles sleeping the proper amount to manage intervals.
@@ -38,13 +38,13 @@ Depending on tunable parameters, these can be threads or processes and can eithe
# Scaling
-This queue architecture allows significant advantages by distributing processing. At each timer execution a generation job gets put in the queue. This queue by default is a Python Queue (either in queue.Queue or multiprocessing.Queue). For details, see the [Performance guide](Performance.md)
+This queue architecture allows significant advantages by distributing processing. At each timer execution a generation job gets put in the queue. This queue by default is a Python Queue (either in queue.Queue or multiprocessing.Queue). For details, see the [Performance guide](PERFORMANCE.md)
# Testing
Given the complexity and the reimplementation of a number of features during refactors, we've also built out a number of test examples. We currently don't have test scripts built with assertions etc, but there are a series of configs and samples under the `tests/` directory which should demonstrate and allow testing of basic functionality. Check out the ``tests/sample_eventgen_conf`` directory in the project for commonly-used plugins and configurations. You can execute a test config by doing:
- python bin/eventgen.py generate tests/
/.conf
+ python -m splunk_eventgen generate tests//.conf
# Server-Controller Architecture
diff --git a/docs/BASICS.md b/docs/BASICS.md
index 4762eb87..b02b1cc3 100644
--- a/docs/BASICS.md
+++ b/docs/BASICS.md
@@ -7,14 +7,17 @@ This should hopefully get you through setting up a working eventgen instance. Fo
The first example we'll show you should likely cover 90% of the use cases you can imagine. Eventgen can take an export from another Splunk instance, or just a plain text file, and replay those events while replacing the time stamps. Eventgen will pause the amount of time between each event just like it happened in the original, so the events will appear to be coming out in real time. When Eventgen reaches the end of the file, it will automatically start over from the beginning.
-### Making a Splunk export
+### Making a Splunk Export
-To build a seed for your new Eventgen, I recommend taking an export from an existing Splunk instance. You could also take a regular log file and use it for replay (in which case, you can omit sampletype=csv). There are a few considerations. First, Eventgen assumes its sample files are in chronological order. Second, it only uses index, host, source, sourcetype and \_raw fields. To accommodate that, whatever search you write, we recommend appending '| reverse | fields index, host, source, sourcetype, _raw' to your Splunk search and then doing an export to CSV format. Third, make sure you find all the different time formats inside the log file and set up tokens to replace for them, so limiting your initial search to a few sourcetypes is probably advisable.
+To build a seed for your new Eventgen, I recommend taking an export from an existing Splunk instance. You could also take a regular log file and use it for replay (in which case, you can omit sampletype=csv). There are a few considerations.
+* First, Eventgen assumes its sample files are in chronological order.
+* Second, it only uses `index`, `host`, `source`, `sourcetype` and `_raw` fields. To accommodate that, whatever search you write, we recommend appending `| reverse | fields index, host, source, sourcetype, _raw` to your Splunk search and then doing an export to CSV format.
+* Third, make sure you find all the different time formats inside the log file and set up tokens to replace for them, so limiting your initial search to a few sourcetypes is probably advisable.
### Running the example
-You can easily run these examples by hand. In fact, for testing purposes, I almost always change outputMode = stdout to visually examine the data. Run the command below from the base directory of Eventgen.
+You can easily run these examples by hand. In fact, for testing purposes, I almost always change outputMode = stdout to visually examine the data. Run the command below from directory `$EVENTGEN_HOME/splunk_eventgen`.
- python -m splunk_eventgen generate splunk_eventgen/README/eventgen.conf.tutorial1
+ python -m splunk_eventgen generate README/eventgen.conf.tutorial1
You should now see events showing up on your terminal window. You can see Eventgen will sleep between events as it sees gaps in the events in the source log.
@@ -23,9 +26,9 @@ This will cover most, if not all, of most people's use cases. Find a real world
## Basic Sample
-Next, lets build a basic noise generator from a log file. This will use sample mode, which take a file and replay all or a subset of that file every X seconds, defined by the interval. Sample mode is the original way eventgen ran, and it's still very useful for generating random data where you want to engineer the data generated from the ground up. To run the example:
+Next, lets build a basic noise generator from a log file. This will use sample mode, which take a file and replay all or a subset of that file every X seconds, defined by the interval. Sample mode is the original way eventgen ran, and it's still very useful for generating random data where you want to engineer the data generated from the ground up. Run the command below from directory `$EVENTGEN_HOME/splunk_eventgen`:
- python -m splunk_eventgen generate splunk_eventgen/README/eventgen.conf.tutorial2
+ python -m splunk_eventgen generate README/eventgen.conf.tutorial2
### Grabbing and rating events
@@ -67,7 +70,7 @@ Let's us decide how often we want to generate events and how we want to generate
randomizeEvents = true
Eventgen by default will rate events by the time of day and the day of the week and introduce some randomness every interval. Also by default, we'll only grab the first X events from the log file every time. For this example, we're looking at router and switch events, which actually is the opposite of the normal business flow. We expect to see more events overnight for a few hours during maintenance windows and calm down during the day, so we'll need to override the default rating which looks like a standard business cycle.
-hourOfDayRate is a JSON formatted hash, with a string identifier for the current hour and a float representing the multiplier we want to use for that hour. In general, I've always configured the rate to be between 0 and 1, but nothing limits you from putting it at any valid floating point value. dayOfWeekRate is similar, but the number is the day of the week, starting with Sunday. In this example, Saturday and Sunday early mornings should have the greatest number of events, with fewer events evenly distributed during the week. randomizeCount says to introduce 20% randomess, which means plus or minus 10% of the rated total, to every rated count just to make sure we don't have a flat rate of events. randomizeEvents we discussed previously, it makes sure we don't grab the same lines from the file every time.
+`hourOfDayRate` is a JSON formatted hash, with a string identifier for the current hour and a float representing the multiplier we want to use for that hour. In general, I've always configured the rate to be between 0 and 1, but nothing limits you from putting it at any valid floating point value. `dayOfWeekRate` is similar, but the number is the day of the week, starting with Sunday. In this example, Saturday and Sunday early mornings should have the greatest number of events, with fewer events evenly distributed during the week. `randomizeCount` says to introduce 20% randomness, which means plus or minus 10% of the rated total, to every rated count just to make sure we don't have a flat rate of events. `randomizeEvents` we discussed previously, it makes sure we don't grab the same lines from the file every time.
outputMode = file
fileName = /tmp/ciscosample.log
@@ -81,7 +84,7 @@ As we've seen before, here's a simple token substitution for the timestamp. Thi
Let's look in detail at this configuration format. token is the configuration statement, 0 is the token number (we'll want a different number for every token we define, although they can be non-contiguous). The third part defines the three subitems of token configuration. The first, token, defines a regular expression we're going to look for in the events as they stream through Eventgen. The second, replacementType, defines what type of replacement we're going to need. This is a timestamp, but we also offer a variety of other token replacement types such as random for randomly generated values, file for grabbing lines out of files, static for replacing with static strings, etc. We'll cover those in detail later. The third subitem, replacement, is specific for the replacementType, and in this case defines a strptime format we're going to use to output the time using strftime. For a reference on how to configure strptime, check python's documentation on strptime format strings.
-This should now replay random events from the file we have configured. Go ahead and cd to $EVENTGEN\_HOME/bin and run python eventgen.py ../README/eventgen.conf.tutorial1. In another shell, tail -f /tmp/ciscosample.log and you should see events replaying from the cisco.sample file! You can reuse this same example to easily replay a customer log file, of course accounting for the different regular expressions and strptime formats you'll need for their timestamps. Remember to customize interval, earliest, and count for the number of events you want the generator to build.
+This should now replay random events from the file we have configured. Go ahead and cd to `$EVENTGEN_HOME/splunk_eventgen` and run `python -m splunk_eventgen generate README/eventgen.conf.tutorial1`. In another shell, tail -f /tmp/ciscosample.log and you should see events replaying from the cisco.sample file! You can reuse this same example to easily replay a customer log file, of course accounting for the different regular expressions and strptime formats you'll need for their timestamps. Remember to customize interval, earliest, and count for the number of events you want the generator to build.
## Second example, building events from scratch
@@ -151,7 +154,7 @@ Note here that we've specified index, host, source and sourceType. In the past
### Defining tokens
-If you look at the sample.tutorial3 file, you'll see that we took just one sample event and placed it in the file. Eventgen will look at this one event, continue to replay it a number of times defined by our rating parameters, and then substitute in tokens we're going to define. First, let's get the one token we understand out of the way, the timestamp:
+If you look at the `sample.tutorial3` file, you'll see that we took just one sample event and placed it in the file. Eventgen will look at this one event, continue to replay it a number of times defined by our rating parameters, and then substitute in tokens we're going to define. First, let's get the one token we understand out of the way, the timestamp:
token.0.token = \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3}
token.0.replacementType = timestamp
@@ -237,29 +240,27 @@ Secondly, in the replacement clause, we have a JSON formatted list. This allows
## Command Line
-This revision of Eventgen can be run by itself from a command line for testing. This means you can simply run bin/eventgen.py and start seeing output, which is great for testing. Please note to do this you'll want to set the $SPLUNK\_HOME environment variable properly so your configurations will work. **Command Line and Embedded Defaults are defined in the lib/eventgen\_defaults file in the [global] stanza**.
+This revision of Eventgen can be run by itself from a command line for testing. This means you can simply run `splunk_eventgen generate eventgen.conf` and start seeing output, which is great for testing. **Command Line and Embedded Defaults are defined in the `splunk_eventgen/default/eventgen.conf` file in the [global] stanza**.
## Splunk App
-The original SA-Eventgen was written as a Splunk app, and this Eventgen release supports that deployment method as well. In this deployment method, we will read configurations through Splunk's internal REST interface for grabbing config info, and Eventgen will look for configurations in every installed apps default and local directories in eventgen.conf file. This is how ES is deployed, and it provides a very good example of this deployment method. If you are writing a complicated Splunk application which will be deployed in multiple Applications, like ES, this is the recommended deployment method as it will simply your needs of building scripted inputs for each of those individual applications. Installed a separate application, there is also a setup.xml provided which allows for easy disabling of the scripted input in Eventgen application. **Defaults are defined in the default/eventgen.conf file in App mode**.
+The original `SA-Eventgen` was written as a Splunk app, and this Eventgen release supports that deployment method as well. In this deployment method, we will read configurations through Splunk's internal REST interface for grabbing config info, and Eventgen will look for configurations in every installed apps default and local directories in `eventgen.conf` file. This is how ES is deployed, and it provides a very good example of this deployment method. If you are writing a complicated Splunk application which will be deployed in multiple Applications, like ES, this is the recommended deployment method.
-In your app's eventgen.conf file, sample files for file, mvfile and seqfile substitution should be referenced using `$SPLUNK_HOME/etc/apps//samples/`.
+Install the latest SA-Eventgen App. There is no additional configuration required. SA-Eventgen app will automatically identify with any apps with `eventgen.conf`.
-## Scripted Input
+To start generating data, simply enable the SA-Eventgen modinput by going to Settings > Data Inputs > SA-Eventgen and by clicking "enable" on the default modular input stanza.
-If you are writing an Eventgen for one application, like the Operational Intelligence demo, bundling two applications together is more complex than required and complicates distribution. In this case, Eventgen supports being deployed as a scripted input inside your application. **Note, you must set 'passAuth = splunk-system-user' in your inputs.conf for this to work**. An example inputs.conf entry:
+If you wish you add your bundle so that the modinput can detect your package:
+Package your `eventgen.conf` and sample files into a directory structure as outlined in the [configuration](CONFIGURE.md). After that's done, copy/move the bundle into your `${SPLUNK_HOME}/etc/apps/` directory and restart Splunk. If you have specific samples enabled in your `eventgen.conf`, you should see data streaming into the specified Splunk index.
- [script://./bin/eventgen.py]
- disabled = false
- interval = 300
- passAuth = splunk-system-user
- sourcetype = eventgen
- index = _internal
-
-Note, the interval can be set to anything. Eventgen will stay running as soon as Splunk launches it. To embed Eventgen into your application, you need to include everything in the bin and lib directories in your application. In Scripted Input mode, we also read eventgen-standalone.conf in the default and local directories, and again **it will not flatten these configurations, so the local file will completely override the default**. It is recommended that when deploying standalone, you only write one configuration file in the local directory. Remember to copy any stock samples you are using into your apps samples directory as well. **Defaults are defined in the lib/eventgen\_defaults file in the [global] stanza**.
-
-In your app's eventgen.conf file, sample files for file, mvfile and seqfile substitution should be referenced using `$SPLUNK_HOME/etc/apps//samples/`.
+Make sure the bundle app permission is global. You can config this in two ways:
+* Log in to Splunk Web and navigate to Apps > Manage Apps. Find the bundle app row and set the permission to 'Global' on the Sharing column.
+* Create a folder `metadata` under the bundle with file `default.meta` and add the following content:
+```
+[]
+export=system
+```
## Wrapping up
-We hope the tutorial covers most use cases you would need. If you have something you're struggling to model, please reach out to Tony Lee (tonyl@splunk.com). We believe we can cover just about anything you'd want to model with this Eventgen, but if not, we're happy to add features to the software so that everyone can benefit!
\ No newline at end of file
+We hope the tutorial covers most use cases you would need. If you have something you're struggling to model, please reach out to Tony Lee (tonyl@splunk.com). We believe we can cover just about anything you'd want to model with this Eventgen, but if not, we're happy to add features to the software so that everyone can benefit!
diff --git a/docs/CONTRIBUTE.md b/docs/CONTRIBUTE.md
new file mode 100644
index 00000000..51135f9b
--- /dev/null
+++ b/docs/CONTRIBUTE.md
@@ -0,0 +1,97 @@
+# Contribute to Eventgen
+
+Please be sure to read the contribution guidelines before making or requesting a change.
+
+## Code of conduct
+
+### Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of experience,
+nationality, personal appearance, race, religion, or sexual identity and
+orientation.
+
+### Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+
+### Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+### Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+### Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at tonyl@splunk.com. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+### Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
+
+## Filing issues
+
+Before filing an issue, please be sure to read the guidelines for what you're reporting:
+
+* [Reporting bugs](FILE_ISSUES.md#reporting-bugs)
+* [Requesting changes](FILE_ISSUES.md#requesting-changes)
+
+
+## Contributing code
+
+Before working on the code, please read over the guidelines about how to contributing code.
+
+* [Pull Request](CONTRIBUTE_CODE.md#pull-request-guidelines)
+* [Build Eventgen](CONTRIBUTE_CODE.md#how-to-build-eventgen)
+* [Code Style](CONTRIBUTE_CODE.md#code-style-and-formatting-tools)
+
+
diff --git a/docs/CONTRIBUTE_CODE.md b/docs/CONTRIBUTE_CODE.md
new file mode 100644
index 00000000..14c4453d
--- /dev/null
+++ b/docs/CONTRIBUTE_CODE.md
@@ -0,0 +1,140 @@
+# Contribute Code To Eventgen
+
+If you want to contribute code to eventgen, please read over the following guidelines before creating any pull request.
+
+
+## Pull request guidelines
+
+
+If you want to contribute to an eventgen repo, please use a GitHub pull request. This is the fastest way for us to evaluate your code and to merge it into the code base. Please don’t file an issue with snippets of code. Doing so means that we need to manually merge the changes in and update any appropriate tests. That decreases the likelihood that your code is going to get included in a timely manner. Please use pull requests.
+
+### Get started
+
+If you’d like to work on a pull request and you’ve never submitted code before, follow these steps:
+1. fork eventgen to your github workspace
+2. If you want to fix bugs or make enhancement, please make sure there is a issue in eventgen project. Refer [this guide](FILE_ISSUES.md) to create a issue.
+
+
+After that, you’re ready to start working on code.
+
+### Working on the code
+
+The process of submitting a pull request is fairly straightforward and generally follows the same pattern each time:
+1. Create a new branch
+2. Make your changes and check into local branch
+3. Rebase onto upstream
+4. Run the test
+5. Push your change
+6. Submit the pull request
+
+#### Step1: Create a new branch
+
+The first step to sending a pull request is to create a new branch in your eventgen fork. Give the branch a descriptive name that describes what it is you’re fixing. Although the branch name can be any words, we highly recommend you to use some descriptive and structured name. It will be good for you to manage the branches when there are many branches in your fork.
+```bash
+# The branch name contains 2 parts. First part works like a label, it describe what type of issue this branch is working on. Second part is the issue id.
+# For example, if the code change is a bug fix
+$ git checkout -b bug/issue123
+# For example, if the code change is to address change request
+$ git checkout -b change/issue123
+# For example, if the code change is only about refine the build process, such as making changes about CICD process
+$ git checkout -b build/issue123
+# For example, if the code change is only about refining the test cases or paying for tech debt
+$ git checkout -b chore/issue123
+```
+
+#### Step2: Make your changes and check into local branch
+
+Once you finished your change, commit them into your local branch.
+```bash
+$ git add -A
+$ git commit
+```
+
+Our commit message format is as follows:
+```
+Tag: Short description (fixes #1234)
+// empty line
+Longer description here if necessary
+```
+
+The first line of the commit message (the summary) must have a specific format. This format is checked by our build tools.
+
+The **Tag** is one of the following:
+
+* **Fix** - for a bug fix.
+* **Update** - update or enhance an existing feature.
+* **New** - implemented a new feature.
+* **Docs** - changes to documentation only.
+* **Build** - changes to build process only, updating the dependency libs etc.
+* **Chore** - for refactoring, adding tests, paying tech debt etc. (anything that isn’t user-facing).
+
+
+Use the labels of the issue you are working on to determine the best tag.
+
+The message summary should be a one-sentence description of the change, and it must be 72 characters in length or shorter. Please make the short description concise. If the pull request addresses an issue, then the issue number should be mentioned at the end. If the commit doesn’t completely fix the issue, then use (refs #1234) instead of (fixes #1234).
+
+**Note**: please squash you changes in one commit before firing the pull request. One commit in one PR keeps the git history clean.
+
+#### Step 3: Rebase onto upstream
+
+Before you send the pull request, be sure to rebase onto the upstream source. This ensures your code is running on the latest available code. We prefer rebase instead of merge when upstream changes. Rebase keeps the git history clearer.
+```bash
+git fetch upstream
+git rebase upstream/master
+```
+
+#### Step 4: Run the tests
+
+The is a place holder as well. We should write about
+* how to run unit test
+* how to run funcional test
+* what is the acceptance criteria about the test
+* how to add test cases
+
+
+#### Step 5: Push your change
+Before pushing the changes, double check your changes follows the [code style](#code-style-and-formatting-tools) and all tests are passed.
+
+
+Next, push your changes to your clone:
+```bash
+git push origin fix/issue123
+```
+
+#### Step 6: Submit the pull request
+
+Before creating a pull request, here are some recommended **check points**.
+
+1. Ensure any install or build dependencies are removed before the end of the layer when doing a
+ build.
+2. Update the splunk_eventgen/README/eventgen.conf.spec with details of changes to the interface, this includes new environment
+ variables, exposed ports, useful file locations and container parameters. Also, update the necessary documentation.
+3. Make sure the build is successful and all test cases are passed.
+4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
+ do not have permission to do that, you may request the second reviewer to merge it for you.
+
+
+Next, create a pull request from your branch to the eventgen develop branch.
+Mark @lephino , @arctan5x , @jmeixensperger , @li-wu , @GordonWang as the reviewers.
+
+
+
+## Code style and formatting tools
+
+Since Eventgen is written in python, we apply a coding style based on [PEP8](https://www.python.org/dev/peps/pep-0008/).
+
+
+**TODO: Add section refrencing the code formatter.**
+
+
+## How to build eventgen
+
+**TODO: consolidate the setup page information into this section.**
+
+### Build eventgen pip module
+
+### Build eventgen splunk app
+
+### Run unit test
+
+### Run functional test
\ No newline at end of file
diff --git a/docs/Dockerfile b/docs/Dockerfile
deleted file mode 100644
index 46e7dff7..00000000
--- a/docs/Dockerfile
+++ /dev/null
@@ -1,30 +0,0 @@
-FROM alpine:3.6
-
-# Install stuff
-RUN apk upgrade --update && \
- apk add --no-cache --update \
- nodejs \
- nodejs-npm \
- curl \
- python3 \
- build-base && \
- rm -rf /var/cache/apk/* && \
- npm install -g npm q gitbook-cli lodash commander optimist bash-color fs-extra
-
-# Copy gitbook files
-COPY *.md /root/
-COPY book.json /root/
-
-# Copy entrypoint
-COPY entrypoint.sh /sbin/entrypoint.sh
-
-# Run gitbook install
-RUN cd /root/ && gitbook install
-
-EXPOSE 4000
-
-HEALTHCHECK --interval=1m --timeout=15s --start-period=1m --retries=3 \
- CMD curl -f http://localhost:4000 || exit 1
-
-WORKDIR /root/
-ENTRYPOINT ["/sbin/entrypoint.sh"]
diff --git a/docs/FILE_ISSUES.md b/docs/FILE_ISSUES.md
new file mode 100644
index 00000000..018d85f6
--- /dev/null
+++ b/docs/FILE_ISSUES.md
@@ -0,0 +1,20 @@
+# Filing Issues For Eventgen
+
+## Reporting bugs
+
+
+If you think you've found a bug in eventgen, please [create a bug report](https://github.com/splunk/eventgen/issues/new/choose) on github.
+
+
+For bugs, please choose the bug report template. Then, provide information as much as possible according to the tempalte. If we need to triage issues and constantly ask people for more detail, that’s time taken away from actually fixing issues. Help us be as efficient as possible by including a lot of detail in your issues.
+
+**Note:** If you just have a question that won’t necessarily result in a change to eventgen, such as asking how something works or how to contribute, please use the slack channel instead of filing an issue.
+
+
+## Requesting changes
+
+
+If you want some enhancement or new feature which is not in current eventgen release, please [create a feature request](https://github.com/splunk/eventgen/issues/new/choose) on github.
+
+
+For change requests, please choose the feature request template. Then, provide the information as much as possible according to the template. When creating a change request issue, please provide clear description about the user scenario and the expected behavior following to the template. It is very important to save the time and avoid back and forth discussion.
\ No newline at end of file
diff --git a/docs/Gemfile b/docs/Gemfile
new file mode 100644
index 00000000..37f5eaa4
--- /dev/null
+++ b/docs/Gemfile
@@ -0,0 +1,2 @@
+source 'https://rubygems.org'
+gem 'github-pages', group: :jekyll_plugins
diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock
new file mode 100644
index 00000000..057c847b
--- /dev/null
+++ b/docs/Gemfile.lock
@@ -0,0 +1,248 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ activesupport (4.2.10)
+ i18n (~> 0.7)
+ minitest (~> 5.1)
+ thread_safe (~> 0.3, >= 0.3.4)
+ tzinfo (~> 1.1)
+ addressable (2.5.2)
+ public_suffix (>= 2.0.2, < 4.0)
+ coffee-script (2.4.1)
+ coffee-script-source
+ execjs
+ coffee-script-source (1.11.1)
+ colorator (1.1.0)
+ commonmarker (0.17.13)
+ ruby-enum (~> 0.5)
+ concurrent-ruby (1.1.5)
+ dnsruby (1.61.2)
+ addressable (~> 2.5)
+ em-websocket (0.5.1)
+ eventmachine (>= 0.12.9)
+ http_parser.rb (~> 0.6.0)
+ ethon (0.12.0)
+ ffi (>= 1.3.0)
+ eventmachine (1.2.7)
+ execjs (2.7.0)
+ faraday (0.15.4)
+ multipart-post (>= 1.2, < 3)
+ ffi (1.10.0)
+ forwardable-extended (2.6.0)
+ gemoji (3.0.0)
+ github-pages (197)
+ activesupport (= 4.2.10)
+ github-pages-health-check (= 1.16.1)
+ jekyll (= 3.7.4)
+ jekyll-avatar (= 0.6.0)
+ jekyll-coffeescript (= 1.1.1)
+ jekyll-commonmark-ghpages (= 0.1.5)
+ jekyll-default-layout (= 0.1.4)
+ jekyll-feed (= 0.11.0)
+ jekyll-gist (= 1.5.0)
+ jekyll-github-metadata (= 2.12.1)
+ jekyll-mentions (= 1.4.1)
+ jekyll-optional-front-matter (= 0.3.0)
+ jekyll-paginate (= 1.1.0)
+ jekyll-readme-index (= 0.2.0)
+ jekyll-redirect-from (= 0.14.0)
+ jekyll-relative-links (= 0.6.0)
+ jekyll-remote-theme (= 0.3.1)
+ jekyll-sass-converter (= 1.5.2)
+ jekyll-seo-tag (= 2.5.0)
+ jekyll-sitemap (= 1.2.0)
+ jekyll-swiss (= 0.4.0)
+ jekyll-theme-architect (= 0.1.1)
+ jekyll-theme-cayman (= 0.1.1)
+ jekyll-theme-dinky (= 0.1.1)
+ jekyll-theme-hacker (= 0.1.1)
+ jekyll-theme-leap-day (= 0.1.1)
+ jekyll-theme-merlot (= 0.1.1)
+ jekyll-theme-midnight (= 0.1.1)
+ jekyll-theme-minimal (= 0.1.1)
+ jekyll-theme-modernist (= 0.1.1)
+ jekyll-theme-primer (= 0.5.3)
+ jekyll-theme-slate (= 0.1.1)
+ jekyll-theme-tactile (= 0.1.1)
+ jekyll-theme-time-machine (= 0.1.1)
+ jekyll-titles-from-headings (= 0.5.1)
+ jemoji (= 0.10.2)
+ kramdown (= 1.17.0)
+ liquid (= 4.0.0)
+ listen (= 3.1.5)
+ mercenary (~> 0.3)
+ minima (= 2.5.0)
+ nokogiri (>= 1.8.5, < 2.0)
+ rouge (= 2.2.1)
+ terminal-table (~> 1.4)
+ github-pages-health-check (1.16.1)
+ addressable (~> 2.3)
+ dnsruby (~> 1.60)
+ octokit (~> 4.0)
+ public_suffix (~> 3.0)
+ typhoeus (~> 1.3)
+ html-pipeline (2.10.0)
+ activesupport (>= 2)
+ nokogiri (>= 1.4)
+ http_parser.rb (0.6.0)
+ i18n (0.9.5)
+ concurrent-ruby (~> 1.0)
+ jekyll (3.7.4)
+ addressable (~> 2.4)
+ colorator (~> 1.0)
+ em-websocket (~> 0.5)
+ i18n (~> 0.7)
+ jekyll-sass-converter (~> 1.0)
+ jekyll-watch (~> 2.0)
+ kramdown (~> 1.14)
+ liquid (~> 4.0)
+ mercenary (~> 0.3.3)
+ pathutil (~> 0.9)
+ rouge (>= 1.7, < 4)
+ safe_yaml (~> 1.0)
+ jekyll-avatar (0.6.0)
+ jekyll (~> 3.0)
+ jekyll-coffeescript (1.1.1)
+ coffee-script (~> 2.2)
+ coffee-script-source (~> 1.11.1)
+ jekyll-commonmark (1.3.1)
+ commonmarker (~> 0.14)
+ jekyll (>= 3.7, < 5.0)
+ jekyll-commonmark-ghpages (0.1.5)
+ commonmarker (~> 0.17.6)
+ jekyll-commonmark (~> 1)
+ rouge (~> 2)
+ jekyll-default-layout (0.1.4)
+ jekyll (~> 3.0)
+ jekyll-feed (0.11.0)
+ jekyll (~> 3.3)
+ jekyll-gist (1.5.0)
+ octokit (~> 4.2)
+ jekyll-github-metadata (2.12.1)
+ jekyll (~> 3.4)
+ octokit (~> 4.0, != 4.4.0)
+ jekyll-mentions (1.4.1)
+ html-pipeline (~> 2.3)
+ jekyll (~> 3.0)
+ jekyll-optional-front-matter (0.3.0)
+ jekyll (~> 3.0)
+ jekyll-paginate (1.1.0)
+ jekyll-readme-index (0.2.0)
+ jekyll (~> 3.0)
+ jekyll-redirect-from (0.14.0)
+ jekyll (~> 3.3)
+ jekyll-relative-links (0.6.0)
+ jekyll (~> 3.3)
+ jekyll-remote-theme (0.3.1)
+ jekyll (~> 3.5)
+ rubyzip (>= 1.2.1, < 3.0)
+ jekyll-sass-converter (1.5.2)
+ sass (~> 3.4)
+ jekyll-seo-tag (2.5.0)
+ jekyll (~> 3.3)
+ jekyll-sitemap (1.2.0)
+ jekyll (~> 3.3)
+ jekyll-swiss (0.4.0)
+ jekyll-theme-architect (0.1.1)
+ jekyll (~> 3.5)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-cayman (0.1.1)
+ jekyll (~> 3.5)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-dinky (0.1.1)
+ jekyll (~> 3.5)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-hacker (0.1.1)
+ jekyll (~> 3.5)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-leap-day (0.1.1)
+ jekyll (~> 3.5)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-merlot (0.1.1)
+ jekyll (~> 3.5)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-midnight (0.1.1)
+ jekyll (~> 3.5)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-minimal (0.1.1)
+ jekyll (~> 3.5)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-modernist (0.1.1)
+ jekyll (~> 3.5)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-primer (0.5.3)
+ jekyll (~> 3.5)
+ jekyll-github-metadata (~> 2.9)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-slate (0.1.1)
+ jekyll (~> 3.5)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-tactile (0.1.1)
+ jekyll (~> 3.5)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-time-machine (0.1.1)
+ jekyll (~> 3.5)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-titles-from-headings (0.5.1)
+ jekyll (~> 3.3)
+ jekyll-watch (2.2.1)
+ listen (~> 3.0)
+ jemoji (0.10.2)
+ gemoji (~> 3.0)
+ html-pipeline (~> 2.2)
+ jekyll (~> 3.0)
+ kramdown (1.17.0)
+ liquid (4.0.0)
+ listen (3.1.5)
+ rb-fsevent (~> 0.9, >= 0.9.4)
+ rb-inotify (~> 0.9, >= 0.9.7)
+ ruby_dep (~> 1.2)
+ mercenary (0.3.6)
+ mini_portile2 (2.4.0)
+ minima (2.5.0)
+ jekyll (~> 3.5)
+ jekyll-feed (~> 0.9)
+ jekyll-seo-tag (~> 2.1)
+ minitest (5.11.3)
+ multipart-post (2.0.0)
+ nokogiri (1.10.2)
+ mini_portile2 (~> 2.4.0)
+ octokit (4.14.0)
+ sawyer (~> 0.8.0, >= 0.5.3)
+ pathutil (0.16.2)
+ forwardable-extended (~> 2.6)
+ public_suffix (3.0.3)
+ rb-fsevent (0.10.3)
+ rb-inotify (0.10.0)
+ ffi (~> 1.0)
+ rouge (2.2.1)
+ ruby-enum (0.7.2)
+ i18n
+ ruby_dep (1.5.0)
+ rubyzip (1.2.2)
+ safe_yaml (1.0.5)
+ sass (3.7.3)
+ sass-listen (~> 4.0.0)
+ sass-listen (4.0.0)
+ rb-fsevent (~> 0.9, >= 0.9.4)
+ rb-inotify (~> 0.9, >= 0.9.7)
+ sawyer (0.8.1)
+ addressable (>= 2.3.5, < 2.6)
+ faraday (~> 0.8, < 1.0)
+ terminal-table (1.8.0)
+ unicode-display_width (~> 1.1, >= 1.1.1)
+ thread_safe (0.3.6)
+ typhoeus (1.3.1)
+ ethon (>= 0.9.0)
+ tzinfo (1.2.5)
+ thread_safe (~> 0.1)
+ unicode-display_width (1.5.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ github-pages
+
+BUNDLED WITH
+ 2.0.1
diff --git a/docs/REFERENCE.md b/docs/REFERENCE.md
index 2b939a14..05ebdd53 100644
--- a/docs/REFERENCE.md
+++ b/docs/REFERENCE.md
@@ -209,6 +209,13 @@ accessToken =
index =
* ONLY VALID WITH outputMode SPLUNKSTREAM
* Splunk index to write events to. Defaults to main if none specified.
+
+extendIndexes = :,,
+ * Sample level setting. Use this setting enable eventgen to generate multi indexes for one sample.
+ * if you set the value with pattern like ":", it will treat as a prefix of an actual index,
+ * and is an integer that indicate the count of index you want to extend for this sample.
+ * eg: events from a sample with "extendIndexes = test_:5, main, web" setting will be added with indexes "test_0, test_1,
+ * test_2, test_3, test_4, main, web" randomly.
source =
* Valid with outputMode=modinput (default) & outputMode=splunkstream & outputMode=httpevent
@@ -266,7 +273,7 @@ sampletype = raw | csv
CSV allows you to override output fields for the sample like host, index, source and sourcetype
from the CSV file. Will read the raw events from a field called _raw. Assumes the CSV file has
a header row which defines field names.
- OVERRIDES FOR DEFAULT FIELDS WILL ONLY WITH WITH outputMode SPLUNKSTREAM.
+ OVERRIDES FOR DEFAULT FIELDS WILL ONLY WORK WITH outputMode SPLUNKSTREAM.
interval =
* Only valid in mode = sample
@@ -359,21 +366,21 @@ dayOfWeekRate =
minuteOfHourRate =
* Takes a JSON hash of 60 minutes of an hour, starting with 0
* Sample JSON:
- { "0": 1, "2": 1...}
+ { "0": 1, "1": 1...}
* If a match is not found, will default to count events
* Also multiplied times dayOfWeekRate, hourOfDateRate, dayOfMonthRate, monthOfYearRate
dayOfMonthRate =
* Takes a JSON hash of 31 days of the month, starting with 1
* Sample JSON:
- { "1": 1, "2": 1...}
+ { "1": 1, "1": 1...}
* If a match is not found, will default to count events
* Also multiplied times dayOfWeekRate, hourOfDateRate, minuteOfHourRate, monthOfYearRate
monthOfYearRate =
- * Takes a JSON hash of 60 minutes of an hour, starting with 0
+ * Takes a JSON hash of 12 months of a year, starting with 1
* Sample JSON:
- { "0": 1, "2": 1...}
+ { "1": 1, "2": 1...}
* If a match is not found, will default to count events
* Also multiplied times dayOfWeekRate, hourOfDateRate, minuteOfHourRate, dayOfMonthRate
@@ -606,4 +613,4 @@ Note, "TARGET_NAME" is a variable that should be replaced by the hostname of Eve
* Example:
```
$ curl http://localhost:9500/volume/egx1 -X POST -d '{"perDayVolume": 200}'
- ```
\ No newline at end of file
+ ```
diff --git a/docs/SETUP.md b/docs/SETUP.md
index 0558b6e6..6c50433c 100644
--- a/docs/SETUP.md
+++ b/docs/SETUP.md
@@ -1,4 +1,4 @@
-## Install ##
+## Install
There are multiple ways to use Eventgen, and you should choose the method that best fits your use case.
Below are the two major ways to use Eventgen - as a PyPI module and as a Splunk App. Follow the instructions below depending on your ideal use:
@@ -36,7 +36,7 @@ Below are the two major ways to use Eventgen - as a PyPI module and as a Splunk
---
-## PyPI Installation / First Run #####
+## PyPI Installation / First Run
To use Eventgen as a PyPI module, you need to either download/clone the source code or install direct from github.
@@ -116,7 +116,7 @@ A quick preface on this mode of operation: due to its complexity, this is only r
---
-## Splunk App Installation / First Run #####
+## Splunk App Installation / First Run
To use Eventgen as a Splunk app, you need a SPL file. This SPL file can be obtained in one of two ways:
1. Through running the "build" process of the splunk_eventgen pypi module
diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md
index a69ffe38..4e09f36f 100644
--- a/docs/SUMMARY.md
+++ b/docs/SUMMARY.md
@@ -1,14 +1,15 @@
# Eventgen
* [Getting Started](SETUP.md)
- * [Install](SETUP.md#install)
- * [Configure](SETUP.md#configure)
+ * [Install](SETUP.md)
+ * [Configure](CONFIGURE.md)
* [Tutorial](TUTORIAL.md)
---
* [Basics](BASICS.md)
* [Plugins](PLUGINS.md)
* [Architecture](ARCHITECTURE.md)
* [Performance](PERFORMANCE.md)
+* [Contributing](CONTRIBUTE.md)
---
* [Reference](REFERENCE.md)
* [eventgen.conf.spec](REFERENCE.md#eventgenconfspec)
diff --git a/docs/TUTORIAL.md b/docs/TUTORIAL.md
index 4710a78e..d51c0d9b 100644
--- a/docs/TUTORIAL.md
+++ b/docs/TUTORIAL.md
@@ -2,10 +2,10 @@
The primary source of configuration done in Eventgen is governed by the `eventgen.conf` file.
-* If deployed using containers, Eventgen will look for eventgen.conf in bundles under the `default` directory. For instance, if your bundle is named "datamix-app", you should archive your eventgen.conf in "datamix-app/default/eventgen.conf".
-* If deployed as a Splunk App, Eventgen will look for eventgen.conf files for every app installed in Splunk, and will generate events for every eventgen.conf file it finds. This is convenient if you want to design event generation into a Technology Addon (TA) or other type of Splunk app. You can ship Eventgen configurations with your app and distribute the Eventgen app separately.
+* If deployed using containers, Eventgen will look for `eventgen.conf` in bundles under the `default` directory. For instance, if your bundle is named `datamix-app`, you should archive your `eventgen.conf` in `datamix-app/default/eventgen.conf`.
+* If deployed as a Splunk App, Eventgen will look for `eventgen.conf` files for every app installed in Splunk, and will generate events for every `eventgen.conf` file it finds. This is convenient if you want to design event generation into a Technology Addon (TA) or other type of Splunk app. You can ship Eventgen configurations with your app and distribute the Eventgen app separately.
-The INI format of eventgen.conf can have one or more stanzas. Each stanza name is a sample file it will be reading from. There a number of options available in each stanza. For instance, breaking down this tutorial file option-by-option, we can see how this file will be used to set up Eventgen:
+The INI format of `eventgen.conf` can have one or more stanzas. Each stanza name is a sample file it will be reading from. There a number of options available in each stanza. For instance, breaking down this tutorial file option-by-option, we can see how this file will be used to set up Eventgen:
```
[sample.tutorial1]
@@ -66,6 +66,8 @@ There are various outputModes available (see the [spec](REFERENCE.md#eventgencon
splunkPass = changeme
```
Parameters for setting up outputMode = splunkstream. This is only required if we want to run Eventgen outside of Splunk. As a Splunk App and running as a scripted input, eventgen will gather this information from Splunk itself. Since we'll be running this from the command line for the tutorial, please customize your username and password in the tutorial.
+Note:
+>When using outputMode=splunkstream for running Eventgen outside of Splunk, use parameter `PYTHONHTTPSVERIFY=0` to ignore the SSL error: `SSLError: [SSL: CERTIFICATE_VERIFY_FAILED]`
```
token.0.token = \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3}
diff --git a/docs/book.json b/docs/book.json
deleted file mode 100644
index 39bf0c28..00000000
--- a/docs/book.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "title": "Eventgen Documentation",
- "gitbook": "3.1.1",
- "plugins": [
- "versions",
- "expand-active-chapter",
- "-sharing",
- "fontsettings"
- ],
- "pluginsConfig": {
- "fontsettings": {
- "theme": "white",
- "family": "sans",
- "size": 1
- },
- "versions": {
- "options": [
- {
- "value": "http://go.sv.splunk.com/egdocs",
- "text": "latest",
- "selected": true
- },
- {
- "value": "http://go.sv.splunk.com/egdocs",
- "text": "develop"
- }
- ]
- }
- }
-}
\ No newline at end of file
diff --git a/docs/entrypoint.sh b/docs/entrypoint.sh
deleted file mode 100755
index c5fbc0fb..00000000
--- a/docs/entrypoint.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if [ "$#" -eq "0" ]; then
- cd /root/
- gitbook build
- cd _book && python3 -m http.server 4000
-else
- "$@"
-fi
diff --git a/docs/index.md b/docs/index.md
index 4da11b23..bc7893f8 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -20,6 +20,7 @@
* [Basics](BASICS.md)
* [Plugins](PLUGINS.md)
* [Architecture](ARCHITECTURE.md)
+* [Contribute](CONTRIBUTE.md)
* [Performance](PERFORMANCE.md)
* [Reference](REFERENCE.md)
* [eventgen.conf.spec](REFERENCE.md#eventgenconfspec)
diff --git a/setup.cfg b/setup.cfg
index ab926b67..0a71e5d1 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,12 +1,22 @@
[flake8]
-exclude = .git,.tox,__pycache__,env,venv,build,dist,docs
+exclude = .git,.tox,__pycache__,env,venv,splunk_eventgen/lib/concurrent,splunk_eventgen/lib/requests_futures
max-line-length = 120
+ignore = E121,E123,E126,E226,E24,E704,W503,W504,E722,E731,W605
+# Includes default ignores, E722 (bare excepts), E731 (lambda usage), and W605 (escape sequences)
[metadata]
description-file = README.md
version-from-file: __init__.py
[yapf]
-based_on_style = pep8
-spaces_before_comment = 4
-split_before_logical_operator = true
+column_limit = 120
+split_all_comma_separated_values = false
+split_before_named_assigns = false
+split_before_first_argument = false
+split_before_expression_after_opening_paren = false
+split_before_closing_bracket = false
+each_dict_entry_on_separate_line = false
+
+[isort]
+# isort/yapf solutions to below files are not compatible
+skip = splunk_eventgen/lib/concurrent,splunk_eventgen/lib/requests_futures
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 3df22c4a..c46fc7e7 100644
--- a/setup.py
+++ b/setup.py
@@ -1,17 +1,16 @@
#!/usr/bin/env python
# encoding: utf-8
-from setuptools import setup
-from setuptools import find_packages
-import splunk_eventgen
+from setuptools import find_packages, setup
+import splunk_eventgen
VERSION = splunk_eventgen.__version__
try:
import pypandoc
long_description = pypandoc.convert('README.md', 'rst')
-except(IOError, ImportError):
+except (IOError, ImportError):
long_description = open('README.md').read()
@@ -27,12 +26,9 @@ def readme():
long_description=long_description,
author='Splunk, Inc.',
classifiers=[
- 'Development Status :: 5 - Production/Stable',
- 'Intended Audience :: Developers',
- 'Topic :: Software Development :: Libraries :: Python Modules',
- 'Topic :: Software Development :: Build Tools',
- 'Topic :: Software Development :: Testing',
- 'Programming Language :: Python',
+ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers',
+ 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Build Tools',
+ 'Topic :: Software Development :: Testing', 'Programming Language :: Python',
'Programming Language :: Python :: 2.7'],
keywords='splunk eventgen container containers docker automation',
entry_points={'console_scripts': ["splunk_eventgen = splunk_eventgen.__main__:main"]},
@@ -55,6 +51,4 @@ def readme():
'pyOpenSSL',
'flake8>=3.7.7',
'yapf>=0.26.0',
- 'isort>=4.3.15'
- ]
- )
+ 'isort>=4.3.15'])
diff --git a/splunk_eventgen/__init__.py b/splunk_eventgen/__init__.py
index 6bbcdcc3..04a51e0b 100644
--- a/splunk_eventgen/__init__.py
+++ b/splunk_eventgen/__init__.py
@@ -3,6 +3,7 @@
import json
import os
+
file_location = os.path.normpath(os.path.realpath(__file__))
VERSION_FILE = "version.json"
VERSION_LOCATION = os.path.normpath(os.path.join(file_location, '..', VERSION_FILE))
@@ -10,7 +11,7 @@
def _get_version(versionfile):
"""
- @param versionfile: File to get the version info from
+ @param versionfile: File to get the version info from
@return: Version Number
"""
with open(VERSION_LOCATION, 'r') as fp:
@@ -19,6 +20,7 @@ def _get_version(versionfile):
fp.close()
return version
+
def _set_dev_version():
"""
Write .dev at the end of version
@@ -33,6 +35,7 @@ def _set_dev_version():
fp.write(json.dumps(json_data))
fp.close()
+
def _set_release_version():
"""
Remove .dev at end of version if it exists
diff --git a/splunk_eventgen/__main__.py b/splunk_eventgen/__main__.py
index c4c5d453..1dd058e9 100644
--- a/splunk_eventgen/__main__.py
+++ b/splunk_eventgen/__main__.py
@@ -6,6 +6,7 @@
import argparse
import errno
+import logging
import os
import shutil
import sys
@@ -16,61 +17,93 @@
FILE_LOCATION = os.path.dirname(os.path.abspath(__file__))
path_prepend = os.path.join(FILE_LOCATION, 'lib')
sys.path.append(path_prepend)
-import __init__ as splunk_eventgen_init
-import logging
-import eventgen_core
+
+import __init__ as splunk_eventgen_init # noqa isort:skip
+import eventgen_core # noqa isort:skip
EVENTGEN_VERSION = splunk_eventgen_init.__version__
logger = logging.getLogger()
+
def parse_args():
"""Parse command line arguments"""
subparser_dict = {}
- parser = argparse.ArgumentParser(prog='Eventgen',
- description='Splunk Event Generation Tool')
+ parser = argparse.ArgumentParser(prog='Eventgen', description='Splunk Event Generation Tool')
parser.add_argument("-v", "--verbosity", action="count", help="increase output verbosity")
parser.add_argument("--version", action='version', default=False, version='%(prog)s ' + EVENTGEN_VERSION)
parser.add_argument("--modinput-mode", default=False)
subparsers = parser.add_subparsers(title='commands', help="valid subcommands", dest='subcommand')
# Generate subparser
generate_subparser = subparsers.add_parser('generate', help="Generate events using a supplied config file")
- generate_subparser.add_argument("configfile", help="Location of eventgen.conf, app folder, or name of an app in $SPLUNK_HOME/etc/apps to run")
+ generate_subparser.add_argument(
+ "configfile", help="Location of eventgen.conf, app folder, or name of an app in $SPLUNK_HOME/etc/apps to run")
generate_subparser.add_argument("-s", "--sample", help="Run specified sample only, disabling all other samples")
generate_subparser.add_argument("--keepoutput", action="store_true", help="Keep original outputMode for the sample")
generate_subparser.add_argument("--devnull", action="store_true", help="Set outputMode to devnull")
- generate_subparser.add_argument("--modinput", action="store_true", help="Set outputMode to modinput, to see metadata")
+ generate_subparser.add_argument("--modinput", action="store_true",
+ help="Set outputMode to modinput, to see metadata")
generate_subparser.add_argument("-c", "--count", type=int, help="Set sample count")
generate_subparser.add_argument("-i", "--interval", type=int, help="Set sample interval")
- generate_subparser.add_argument("-b", "--backfill", help="Set time to backfill from. Note: to use it, send the parameter with space in front like ' -60m'")
- generate_subparser.add_argument("-e", "--end", help="Set time to end generation at or a number of intervals to run. Note: to use it with a time, send the parameter with space in front like ' -10m'")
+ generate_subparser.add_argument("-b", "--backfill", help="Set time to backfill from")
+ generate_subparser.add_argument("-e", "--end", help="Set time to end generation at or a number of intervals to run")
generate_subparser.add_argument("--generators", type=int, help="Number of GeneratorWorkers (mappers)")
generate_subparser.add_argument("--outputters", type=int, help="Number of OutputWorkers (reducers)")
generate_subparser.add_argument("--disableOutputQueue", action="store_true", help="Disable reducer step")
- generate_subparser.add_argument("--multiprocess", action="store_true", help="Use multiprocesing instead of threading")
+ generate_subparser.add_argument("--multiprocess", action="store_true",
+ help="Use multiprocesing instead of threading")
generate_subparser.add_argument("--profiler", action="store_true", help="Turn on cProfiler")
generate_subparser.add_argument("--log-path", type=str, default="{0}/logs".format(FILE_LOCATION))
# Build subparser
build_subparser = subparsers.add_parser('build', help="Will build different forms of sa-eventgen")
- build_subparser.add_argument("--mode", type=str, default="splunk-app", help="Specify what type of package to build, defaults to splunk-app mode.")
+ build_subparser.add_argument("--mode", type=str, default="splunk-app",
+ help="Specify what type of package to build, defaults to splunk-app mode.")
build_subparser.add_argument("--destination", help="Specify where to store the output of the build command.")
- build_subparser.add_argument("--remove", default=True, help="Remove the build directory after completion. Defaults to True")
+ build_subparser.add_argument("--remove", default=True,
+ help="Remove the build directory after completion. Defaults to True")
# WSGI subparser
wsgi_subparser = subparsers.add_parser('wsgi', help="start a wsgi server to interact with eventgen.")
- wsgi_subparser.add_argument("--daemon", action="store_true", help="Daemon will tell the wsgi server to start in a daemon mode and will release the cli.")
+ wsgi_subparser.add_argument(
+ "--daemon", action="store_true",
+ help="Daemon will tell the wsgi server to start in a daemon mode and will release the cli.")
# Service subparser
- service_subparser = subparsers.add_parser('service', help="Run Eventgen as a Nameko service. Parameters for starting this service can be defined as either environment variables or CLI arguments, where environment variables takes precedence. See help for more info.")
- service_subparser.add_argument("--role", "-r", type=str, default=None, required=True, choices=["controller", "server"], help="Define the role for this Eventgen node. Options: master, slave")
- service_subparser.add_argument("--amqp-uri", type=str, default=None, help="Full URI to AMQP endpoint in the format pyamqp://:@:. This can also be set using the environment variable EVENTGEN_AMQP_URI")
- service_subparser.add_argument("--amqp-host", type=str, default=None, help="Specify AMQP hostname. This can also be set using the environment variable EVENTGEN_AMQP_HOST. Default is localhost")
- service_subparser.add_argument("--amqp-port", type=int, default=None, help="Specify AMQP port. This can also be set using the environment variable EVENTGEN_AMQP_PORT. Default is 5672")
- service_subparser.add_argument("--amqp-webport", type=int, default=None, help="Specify AMQP web port. This can also be set using the environment variable EVENTGEN_AMQP_WEBPORT. Default is 15672")
- service_subparser.add_argument("--amqp-user", type=str, default=None, help="Specify AMQP user. This can also be set using the environment variable EVENTGEN_AMQP_USER. Default is 'guest'")
- service_subparser.add_argument("--amqp-pass", type=str, default=None, help="Specify AMQP password. This can also be set using the environment variable EVENTGEN_AMQP_PASS. Default is 'guest'")
- service_subparser.add_argument("--web-server-address", type=str, default=None, help="Specify nameko webserver address. This can also be set using the environment variable EVENTGEN_WEB_SERVER_ADDR. Default is 0.0.0.0:9500")
+ service_subparser = subparsers.add_parser(
+ 'service',
+ help=("Run Eventgen as a Nameko service. Parameters for starting this service can be defined as either env"
+ "variables or CLI arguments, where env variables takes precedence. See help for more info."))
+ service_subparser.add_argument("--role", "-r", type=str, default=None, required=True, choices=[
+ "controller", "server"], help="Define the role for this Eventgen node. Options: master, slave")
+ service_subparser.add_argument(
+ "--amqp-uri", type=str, default=None,
+ help=("Full URI to AMQP endpoint in the format pyamqp://:@:."
+ "This can also be set using the environment variable EVENTGEN_AMQP_URI"))
+ service_subparser.add_argument(
+ "--amqp-host", type=str, default=None,
+ help=("Specify AMQP hostname. This can also be set using the environment variable EVENTGEN_AMQP_HOST." +
+ "Default is localhost"))
+ service_subparser.add_argument(
+ "--amqp-port", type=int, default=None,
+ help=("Specify AMQP port. This can also be set using the environment variable EVENTGEN_AMQP_PORT." +
+ "Default is 5672"))
+ service_subparser.add_argument(
+ "--amqp-webport", type=int, default=None,
+ help=("Specify AMQP web port. This can also be set using the environment variable EVENTGEN_AMQP_WEBPORT." +
+ "Default is 15672"))
+ service_subparser.add_argument(
+ "--amqp-user", type=str, default=None,
+ help=("Specify AMQP user. This can also be set using the environment variable EVENTGEN_AMQP_USER." +
+ "Default is 'guest'"))
+ service_subparser.add_argument(
+ "--amqp-pass", type=str, default=None,
+ help=("Specify AMQP password. This can also be set using the environment variable EVENTGEN_AMQP_PASS." +
+ "Default is 'guest'"))
+ service_subparser.add_argument(
+ "--web-server-address", type=str, default=None,
+ help=("Specify nameko webserver address. This can also be set using the environment variable" +
+ "EVENTGEN_WEB_SERVER_ADDR. Default is 0.0.0.0:9500"))
# Help subparser
# NOTE: Keep this at the end so we can use the subparser_dict.keys() to display valid commands
help_subparser = subparsers.add_parser('help', help="Display usage on a subcommand")
- helpstr = "Help on a specific command, valid commands are: " + ", ".join(subparser_dict.keys() + ["help"])
+ helpstr = "Help on a specific command, valid commands are: " + ", ".join(subparser_dict.keys() + ["help"])
help_subparser.add_argument("command", nargs='?', default="default", help=helpstr)
# add subparsers to the subparser dict, this will be used later for usage / help statements.
subparser_dict['generate'] = generate_subparser
@@ -91,7 +124,7 @@ def parse_args():
if 'subcommand' not in args:
parser.print_help()
sys.exit(2)
-
+
if args.subcommand == "service":
if not args.role:
msg = "Role is undefined. Please specify a role for this Eventgen service using --role/-r."
@@ -120,10 +153,11 @@ def parse_args():
args.configfile = None
return args
+
def wait_for_response(address, webport, timeout=300):
'''
- This function extracts the hostname off the given address in the form ://:@:
- and builds a URL in the form http://:. Using this URL, it tries to verify the endpoint is reachable.
+ Extracts the hostname off the given address in the form ://:@: and
+ builds a URL in the form http://:. Using this URL, it tries to verify the endpoint is reachable.
Retry will occur for ~300s
'''
@@ -133,12 +167,12 @@ def wait_for_response(address, webport, timeout=300):
userid, password = creds.split(":")
start = time.time()
end = start
- while end-start < timeout:
+ while end - start < timeout:
try:
r = requests.get("http://{}:{}".format(host, webport))
r.raise_for_status()
return
- except requests.exceptions.ConnectionError as e:
+ except requests.exceptions.ConnectionError:
time.sleep(1)
finally:
end = time.time()
@@ -146,6 +180,7 @@ def wait_for_response(address, webport, timeout=300):
logger.exception(msg)
raise Exception(msg)
+
def parse_cli_vars(config, args):
config["AMQP_URI"] = args.amqp_uri if args.amqp_uri else config["AMQP_URI"]
config["AMQP_HOST"] = args.amqp_host if args.amqp_host else config["AMQP_HOST"]
@@ -156,6 +191,7 @@ def parse_cli_vars(config, args):
config["WEB_SERVER_ADDRESS"] = args.web_server_address if args.web_server_address else config["WEB_SERVER_ADDRESS"]
return config
+
def parse_env_vars():
osvars, config = dict(os.environ), {}
config["AMQP_URI"] = osvars.get("EVENTGEN_AMQP_URI", None)
@@ -167,6 +203,7 @@ def parse_env_vars():
config["WEB_SERVER_ADDRESS"] = osvars.get("EVENTGEN_WEB_SERVER_ADDR", "0.0.0.0:9500")
return config
+
def rectify_config(config):
# For nameko purposes, all we need to pass into the config is AMQP_URI and WEB_SERVER_ADDRESS.
new = {}
@@ -176,22 +213,21 @@ def rectify_config(config):
new["AMQP_URI"] = config["AMQP_URI"]
else:
if all([config["AMQP_HOST"], config["AMQP_PORT"], config["AMQP_USER"], config["AMQP_PASS"]]):
- new["AMQP_URI"] = "pyamqp://{user}:{pw}@{host}:{port}".format(user=config["AMQP_USER"],
- pw=config["AMQP_PASS"],
- host=config["AMQP_HOST"],
- port=config["AMQP_PORT"])
+ new["AMQP_URI"] = "pyamqp://{user}:{pw}@{host}:{port}".format(
+ user=config["AMQP_USER"], pw=config["AMQP_PASS"], host=config["AMQP_HOST"], port=config["AMQP_PORT"])
else:
msg = "AMQP_URI is not defined and cannot be constructed. Check environment variables/CLI arguments."
logger.exception(msg)
raise Exception(msg)
return new
+
def run_nameko(args):
# Running nameko imports here so that Eventgen as a module does not require nameko to run.
import eventlet
eventlet.monkey_patch()
from nameko.runners import ServiceRunner
- # In order to make this run locally as well as within a container-ized environment, we're to pull variables
+ # In order to make this run locally as well as within a container-ized environment, we're to pull variables
# from both environment variables and CLI arguments, where CLI will take precendence.
config = parse_env_vars()
config = parse_cli_vars(config, args)
@@ -229,6 +265,7 @@ def run_nameko(args):
# runner.wait completed
break
+
def exclude_function(filename):
# removing any hidden . files.
last_index = filename.rfind('/')
@@ -240,13 +277,15 @@ def exclude_function(filename):
else:
return False
+
def make_tarfile(output_filename, source_dir):
import tarfile
with tarfile.open(output_filename, "w:gz") as tar:
tar.add(source_dir, arcname=os.path.basename(source_dir), exclude=exclude_function)
+
def build_splunk_app(dest, source=os.getcwd(), remove=True):
- import errno, imp
+ import imp
cwd = os.getcwd()
os.chdir(source)
directory = os.path.join(dest, 'SA-Eventgen')
@@ -275,6 +314,7 @@ def build_splunk_app(dest, source=os.getcwd(), remove=True):
shutil.rmtree(directory)
os.chdir(cwd)
+
def convert_verbosity_count_to_logging_level(verbosity):
if verbosity == 0:
return logging.ERROR
@@ -285,6 +325,7 @@ def convert_verbosity_count_to_logging_level(verbosity):
else:
return logging.ERROR
+
def main():
cwd = os.getcwd()
args = parse_args()
diff --git a/splunk_eventgen/eventgen_core.py b/splunk_eventgen/eventgen_core.py
index e9db47f6..71c80647 100644
--- a/splunk_eventgen/eventgen_core.py
+++ b/splunk_eventgen/eventgen_core.py
@@ -1,17 +1,19 @@
#!/usr/bin/env python
# encoding: utf-8
-from lib.eventgenconfig import Config
-from lib.eventgentimer import Timer
-from lib.eventgenexceptions import PluginNotLoaded, FailedLoadingPlugin
-from lib.outputcounter import OutputCounter
+import imp
+import json
import logging
import logging.config
import os
import sys
-import imp
-from Queue import Queue, Empty
-from threading import Thread
import time
+from Queue import Empty, Queue
+from threading import Thread
+
+from lib.eventgenconfig import Config
+from lib.eventgenexceptions import PluginNotLoaded
+from lib.eventgentimer import Timer
+from lib.outputcounter import OutputCounter
lib_path_prepend = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'lib')
sys.path.insert(0, lib_path_prepend)
@@ -26,23 +28,24 @@
import logutils
import logutils.queue
-file_path=os.path.dirname(os.path.realpath(__file__))
+file_path = os.path.dirname(os.path.realpath(__file__))
EVENTGEN_DIR = os.path.realpath(os.path.join(file_path, ".."))
EVENTGEN_ENGINE_CONF_PATH = os.path.abspath(os.path.join(file_path, "default", "eventgen_engine.conf"))
-import json
+
class JSONFormatter(logging.Formatter):
"""
Quick and dirty formatter that turns the log into a quick json format
"""
+
def format(self, record):
message = record.msg
if not isinstance(message, dict):
- #The record is probably a string
+ # The record is probably a string
try:
message = json.loads(message)
except ValueError:
- #Abort, just store the message as an attribute
+ # Abort, just store the message as an attribute
message = {"message": message}
if "timestamp" not in message:
@@ -51,8 +54,9 @@ def format(self, record):
message["level"] = logging.getLevelName(record.levelno)
return json.dumps(message)
+
class EventGenerator(object):
- def __init__(self, args=None ):
+ def __init__(self, args=None):
'''
This object will allow you to generate and control eventgen. It should be handed the parse_args object
from __main__ and will hand the argument object to the config parser of eventgen5. This will provide the
@@ -81,12 +85,11 @@ def _load_config(self, configfile, **kwargs):
:param configfile:
:return:
'''
- #TODO: The old eventgen had strange cli args, and usage of args. We should probably update the module args
- #to match more of what this is doing...
- new_args={}
+ # TODO: The old eventgen had strange cli args. We should probably update the module args to match this usage.
+ new_args = {}
if "args" in kwargs:
args = kwargs["args"]
- outputer = [key for key in ["keepoutput","devnull","modinput"] if getattr(args, key)]
+ outputer = [key for key in ["keepoutput", "devnull", "modinput"] if getattr(args, key)]
if len(outputer) > 0:
new_args["override_outputter"] = outputer[0]
if getattr(args, "count"):
@@ -112,7 +115,7 @@ def _load_config(self, configfile, **kwargs):
self.config = Config(configfile, **new_args)
self.config.parse()
self._reload_plugins()
- #TODO: Probably should destroy pools better so processes are cleaned.
+ # TODO: Probably should destroy pools better so processes are cleaned.
self._setup_pools()
def _reload_plugins(self):
@@ -120,11 +123,14 @@ def _reload_plugins(self):
# Plugins must be loaded before objects that do work, otherwise threads and processes generated will not have
# the modules loaded in active memory.
try:
- self.config.outputPlugins = { }
- plugins = self._initializePlugins(os.path.join(file_path, 'lib', 'plugins', 'output'), self.config.outputPlugins, 'output')
+ self.config.outputPlugins = {}
+ plugins = self._initializePlugins(
+ os.path.join(file_path, 'lib', 'plugins', 'output'), self.config.outputPlugins, 'output')
self.config.validOutputModes.extend(plugins)
- self._initializePlugins(os.path.join(file_path, 'lib', 'plugins', 'generator'), self.config.plugins, 'generator')
- plugins = self._initializePlugins(os.path.join(file_path, 'lib', 'plugins', 'rater'), self.config.plugins, 'rater')
+ self._initializePlugins(
+ os.path.join(file_path, 'lib', 'plugins', 'generator'), self.config.plugins, 'generator')
+ plugins = self._initializePlugins(
+ os.path.join(file_path, 'lib', 'plugins', 'rater'), self.config.plugins, 'rater')
self.config._complexSettings['rater'] = plugins
except Exception as e:
self.logger.exception(e)
@@ -133,13 +139,12 @@ def _load_custom_plugins(self, PluginNotLoadedException):
plugintype = PluginNotLoadedException.type
plugin = PluginNotLoadedException.name
bindir = PluginNotLoadedException.bindir
- libdir = PluginNotLoadedException.libdir
plugindir = PluginNotLoadedException.plugindir
pluginsdict = self.config.plugins if plugintype in ('generator', 'rater') else self.config.outputPlugins
- #APPPERF-263: be picky when loading from an app bindir (only load name)
+ # APPPERF-263: be picky when loading from an app bindir (only load name)
self._initializePlugins(bindir, pluginsdict, plugintype, name=plugin)
- #APPPERF-263: be greedy when scanning plugin dir (eat all the pys)
+ # APPPERF-263: be greedy when scanning plugin dir (eat all the pys)
self._initializePlugins(plugindir, pluginsdict, plugintype)
def _setup_pools(self):
@@ -165,31 +170,33 @@ def _create_timer_threadpool(self, threadcount=100):
self.sampleQueue = Queue(maxsize=0)
num_threads = threadcount
for i in range(num_threads):
- worker = Thread(target=self._worker_do_work,
- args=(self.sampleQueue, self.loggingQueue, ),
- name="TimeThread{0}".format(i))
+ worker = Thread(target=self._worker_do_work, args=(
+ self.sampleQueue,
+ self.loggingQueue,
+ ), name="TimeThread{0}".format(i))
worker.setDaemon(True)
worker.start()
def _create_output_threadpool(self, threadcount=1):
'''
the output thread pool is used for output plugins that need to control file locking, or only have 1 set thread
- to send all the data out of. this FIFO queue just helps make sure there are file collisions or write collisions.
+ to send all the data out of. This FIFO queue just helps make sure there are file collisions or write collisions.
There's only 1 active thread for this queue, if you're ever considering upping this, don't. Just shut off the
outputQueue and let each generator directly output it's data.
:param threadcount: is how many active output threads we want to allow inside of eventgen. Default 1
:return:
'''
- #TODO: Make this take the config param and figure out what we want to do with this.
+ # TODO: Make this take the config param and figure out what we want to do with this.
if getattr(self, "manager", None):
self.outputQueue = self.manager.Queue(maxsize=500)
else:
self.outputQueue = Queue(maxsize=500)
num_threads = threadcount
for i in range(num_threads):
- worker = Thread(target=self._worker_do_work,
- args=(self.outputQueue, self.loggingQueue, ),
- name="OutputThread{0}".format(i))
+ worker = Thread(target=self._worker_do_work, args=(
+ self.outputQueue,
+ self.loggingQueue,
+ ), name="OutputThread{0}".format(i))
worker.setDaemon(True)
worker.start()
@@ -206,7 +213,7 @@ def _create_generator_pool(self, workercount=20):
import multiprocessing
self.manager = multiprocessing.Manager()
self.loggingQueue = self.manager.Queue()
- self.logging_pool = Thread(target=self.logger_thread, args=(self.loggingQueue,), name="LoggerThread")
+ self.logging_pool = Thread(target=self.logger_thread, args=(self.loggingQueue, ), name="LoggerThread")
self.logging_pool.start()
# since we're now in multiprocess, we need to use better queues.
self.workerQueue = multiprocessing.JoinableQueue(maxsize=500)
@@ -220,7 +227,8 @@ def _create_generator_pool(self, workercount=20):
for i in range(workercount):
self.output_counters.append(OutputCounter())
for i in range(worker_threads):
- worker = Thread(target=self._generator_do_work, args=(self.workerQueue, self.loggingQueue, self.output_counters[i]))
+ worker = Thread(target=self._generator_do_work, args=(self.workerQueue, self.loggingQueue,
+ self.output_counters[i]))
worker.setDaemon(True)
worker.start()
else:
@@ -234,9 +242,12 @@ def _create_generator_workers(self, workercount=20):
import multiprocessing
self.workerPool = []
for worker in xrange(workercount):
- #builds a list of tuples to use the map function
- process = multiprocessing.Process(target=self._proc_worker_do_work,
- args=(self.workerQueue, self.loggingQueue, self.genconfig, ))
+ # builds a list of tuples to use the map function
+ process = multiprocessing.Process(target=self._proc_worker_do_work, args=(
+ self.workerQueue,
+ self.loggingQueue,
+ self.genconfig,
+ ))
self.workerPool.append(process)
process.start()
else:
@@ -262,23 +273,28 @@ def _setup_loggers(self, args=None, config=None):
console_handler.setFormatter(detailed_formatter)
console_handler.setLevel(logging.DEBUG)
- file_handler = logging.handlers.RotatingFileHandler(eventgen_main_logger_path, maxBytes=2500000, backupCount=20)
+ file_handler = logging.handlers.RotatingFileHandler(eventgen_main_logger_path, maxBytes=2500000,
+ backupCount=20)
file_handler.setFormatter(detailed_formatter)
file_handler.setLevel(logging.DEBUG)
- eventgen_controller_file_handler = logging.handlers.RotatingFileHandler(eventgen_controller_logger_path, maxBytes=2500000, backupCount=20)
+ eventgen_controller_file_handler = logging.handlers.RotatingFileHandler(eventgen_controller_logger_path,
+ maxBytes=2500000, backupCount=20)
eventgen_controller_file_handler.setFormatter(detailed_formatter)
eventgen_controller_file_handler.setLevel(logging.DEBUG)
- error_file_handler = logging.handlers.RotatingFileHandler(eventgen_error_logger_path, maxBytes=2500000, backupCount=20)
+ error_file_handler = logging.handlers.RotatingFileHandler(eventgen_error_logger_path, maxBytes=2500000,
+ backupCount=20)
error_file_handler.setFormatter(detailed_formatter)
error_file_handler.setLevel(logging.ERROR)
- metrics_file_handler = logging.handlers.RotatingFileHandler(eventgen_metrics_logger_path, maxBytes=2500000, backupCount=20)
+ metrics_file_handler = logging.handlers.RotatingFileHandler(eventgen_metrics_logger_path, maxBytes=2500000,
+ backupCount=20)
metrics_file_handler.setFormatter(json_formatter)
metrics_file_handler.setLevel(logging.INFO)
- server_file_handler = logging.handlers.RotatingFileHandler(eventgen_server_logger_path, maxBytes=2500000, backupCount=10)
+ server_file_handler = logging.handlers.RotatingFileHandler(eventgen_server_logger_path, maxBytes=2500000,
+ backupCount=10)
server_file_handler.setFormatter(json_formatter)
server_file_handler.setLevel(logging.INFO)
@@ -321,10 +337,12 @@ def _setup_loggers(self, args=None, config=None):
# We need to have debugv from the olderversions of eventgen.
DEBUG_LEVELV_NUM = 9
logging.addLevelName(DEBUG_LEVELV_NUM, "DEBUGV")
+
def debugv(self, message, *args, **kws):
# Yes, logger takes its '*args' as 'args'.
if self.isEnabledFor(DEBUG_LEVELV_NUM):
self._log(DEBUG_LEVELV_NUM, message, args, **kws)
+
logging.Logger.debugv = debugv
self.logger = logging.getLogger('eventgen')
self.loggingQueue = None
@@ -344,6 +362,7 @@ def _worker_do_work(self, work_queue, logging_queue):
except Exception as e:
self.logger.exception(e)
raise e
+
def _generator_do_work(self, work_queue, logging_queue, output_counter=None):
while not self.stopping:
try:
@@ -408,13 +427,13 @@ def _initializePlugins(self, dirname, plugins, plugintype, name=None):
syspathset = set(sys.path)
dirname = os.path.abspath(dirname)
- self.logger.debugv("looking for plugin(s) in {}".format(dirname))
+ self.logger.debug("looking for plugin(s) in {}".format(dirname))
if not os.path.isdir(dirname):
- self.logger.debugv("directory {} does not exist ... moving on".format(dirname))
+ self.logger.debug("directory {} does not exist ... moving on".format(dirname))
return ret
# Include all plugin directories in sys.path for includes
- if not dirname in sys.path:
+ if dirname not in sys.path:
syspathset.add(dirname)
sys.path = list(syspathset)
@@ -429,16 +448,16 @@ def _initializePlugins(self, dirname, plugins, plugintype, name=None):
base, extension = os.path.splitext(basename)
# If we're a python file and we don't start with _
- #if extension == ".py" and not basename.startswith("_"):
+ # if extension == ".py" and not basename.startswith("_"):
# APPPERF-263: If name param is supplied, only attempt to load
# {name}.py from {app}/bin directory
if extension == ".py" and ((name is None and not basename.startswith("_")) or base == name):
- self.logger.debugv("Searching for plugin in file '%s'" % filename)
+ self.logger.debug("Searching for plugin in file '%s'" % filename)
try:
# Import the module
- #module = imp.load_source(base, filename)
+ # module = imp.load_source(base, filename)
mod_name, mod_path, mod_desc = imp.find_module(base, [dirname])
- #TODO: Probably need to adjust module.load() to be added later so this can be pickled.
+ # TODO: Probably need to adjust module.load() to be added later so this can be pickled.
module = imp.load_module(base, mod_name, mod_path, mod_desc)
plugin = module.load()
@@ -487,33 +506,36 @@ def start(self, join_after_start=True):
self.logger.info("No samples found. Exiting.")
for s in self.config.samples:
if s.interval > 0 or s.mode == 'replay' or s.end != "0":
- self.logger.info("Creating timer object for sample '%s' in app '%s'" % (s.name, s.app) )
+ self.logger.info("Creating timer object for sample '%s' in app '%s'" % (s.name, s.app))
# This is where the timer is finally sent to a queue to be processed. Needs to move to this object.
try:
- t = Timer(1.0, sample=s, config=self.config,
- genqueue=self.workerQueue, outputqueue=self.outputQueue, loggingqueue=self.loggingQueue)
+ t = Timer(1.0, sample=s, config=self.config, genqueue=self.workerQueue,
+ outputqueue=self.outputQueue, loggingqueue=self.loggingQueue)
except PluginNotLoaded as pnl:
self._load_custom_plugins(pnl)
- t = Timer(1.0, sample=s, config=self.config,
- genqueue=self.workerQueue, outputqueue=self.outputQueue, loggingqueue=self.loggingQueue)
+ t = Timer(1.0, sample=s, config=self.config, genqueue=self.workerQueue,
+ outputqueue=self.outputQueue, loggingqueue=self.loggingQueue)
except Exception as e:
raise e
self.sampleQueue.put(t)
if join_after_start:
self.logger.info("All timers started, joining queue until it's empty.")
self.join_process()
- ## Only need to start timers once
+ # Only need to start timers once
# Every 5 seconds, get values and output basic statistics about our operations
- #TODO: Figure out how to do this better...
- #generatorsPerSec = (generatorDecrements - generatorQueueCounter) / 5
- #outputtersPerSec = (outputDecrements - outputQueueCounter) / 5
- #outputQueueCounter = outputDecrements
- #generatorQueueCounter = generatorDecrements
- #self.logger.info('OutputQueueDepth=%d GeneratorQueueDepth=%d GeneratorsPerSec=%d OutputtersPerSec=%d' % (self.config.outputQueueSize.value(), self.config.generatorQueueSize.value(), generatorsPerSec, outputtersPerSec))
- #kiloBytesPerSec = self.config.bytesSent.valueAndClear() / 5 / 1024
- #gbPerDay = (kiloBytesPerSec / 1024 / 1024) * 60 * 60 * 24
- #eventsPerSec = self.config.eventsSent.valueAndClear() / 5
- #self.logger.info('GlobalEventsPerSec=%s KilobytesPerSec=%1f GigabytesPerDay=%1f' % (eventsPerSec, kiloBytesPerSec, gbPerDay))
+ # TODO: Figure out how to do this better...
+ # generatorsPerSec = (generatorDecrements - generatorQueueCounter) / 5
+ # outputtersPerSec = (outputDecrements - outputQueueCounter) / 5
+ # outputQueueCounter = outputDecrements
+ # generatorQueueCounter = generatorDecrements
+ # self.logger.info('OutputQueueDepth=%d GeneratorQueueDepth=%d GeneratorsPerSec=%d OutputtersPerSec=%d' %
+ # (self.config.outputQueueSize.value(), self.config.generatorQueueSize.value(),
+ # generatorsPerSec, outputtersPerSec))
+ # kiloBytesPerSec = self.config.bytesSent.valueAndClear() / 5 / 1024
+ # gbPerDay = (kiloBytesPerSec / 1024 / 1024) * 60 * 60 * 24
+ # eventsPerSec = self.config.eventsSent.valueAndClear() / 5
+ # self.logger.info('GlobalEventsPerSec=%s KilobytesPerSec=%1f GigabytesPerDay=%1f' %
+ # (eventsPerSec, kiloBytesPerSec, gbPerDay))
def join_process(self):
'''
@@ -522,7 +544,8 @@ def join_process(self):
:return:
'''
try:
- while not self.sampleQueue.empty() or self.sampleQueue.unfinished_tasks > 0 or not self.workerQueue.empty() or self.workerQueue.unfinished_tasks > 0:
+ while not self.sampleQueue.empty() or self.sampleQueue.unfinished_tasks > 0 or not self.workerQueue.empty(
+ ) or self.workerQueue.unfinished_tasks > 0:
time.sleep(5)
self.logger.info("All timers have finished, signalling workers to exit.")
self.stop()
@@ -538,13 +561,13 @@ def stop(self):
self.logger.info("All timers exited, joining generation queue until it's empty.")
self.workerQueue.join()
- # if we're in multiprocess, make sure that since all the timers stopped, we don't let any more generators get added.
+ # if we're in multiprocess, make sure we don't add more generators after the timers stopped.
if self.args.multiprocess:
self.genconfig["stopping"] = True
for worker in self.workerPool:
count = 0
# We wait for a minute until terminating the worker
- while worker.exitcode == None and count != 20:
+ while worker.exitcode is None and count != 20:
if count == 30:
self.logger.info("Terminating worker {0}".format(worker._name))
worker.terminate()
@@ -586,4 +609,3 @@ def check_running(self):
else:
return True
return False
-
diff --git a/splunk_eventgen/eventgen_nameko_controller.py b/splunk_eventgen/eventgen_nameko_controller.py
index 12cda2e7..52192859 100644
--- a/splunk_eventgen/eventgen_nameko_controller.py
+++ b/splunk_eventgen/eventgen_nameko_controller.py
@@ -1,22 +1,26 @@
-from nameko.rpc import rpc
-from nameko.events import EventDispatcher, event_handler, BROADCAST
-from nameko.web.handlers import http
-from pyrabbit.api import Client
import atexit
+import json
import logging
import os
import socket
-from logger.logger_config import controller_logger_config
import time
-import json
+
+from pyrabbit.api import Client
+
+from logger.logger_config import controller_logger_config
+from nameko.events import BROADCAST, EventDispatcher, event_handler
+from nameko.rpc import rpc
+from nameko.web.handlers import http
FILE_PATH = os.path.dirname(os.path.realpath(__file__))
EVENTGEN_ENGINE_CONF_PATH = os.path.abspath(os.path.join(FILE_PATH, "default", "eventgen_engine.conf"))
+
def exit_handler(client, hostname, logger):
client.delete_vhost(hostname)
logger.info("Deleted vhost {}. Shutting down.".format(hostname))
+
class EventgenController(object):
name = "eventgen_controller"
@@ -38,17 +42,14 @@ class EventgenController(object):
config["AMQP_PASS"] = osvars.get("EVENTGEN_AMQP_PASS", "guest")
pyrabbit_cl = Client('{0}:{1}'.format(config['AMQP_HOST'], config['AMQP_WEBPORT']),
- '{0}'.format(config['AMQP_USER']),
- '{0}'.format(config['AMQP_PASS']))
+ '{0}'.format(config['AMQP_USER']), '{0}'.format(config['AMQP_PASS']))
pyrabbit_cl.create_vhost(host)
log.info("Vhost set to {}".format(host))
log.info("Current Vhosts are {}".format(pyrabbit_cl.get_vhost_names()))
atexit.register(exit_handler, client=pyrabbit_cl, hostname=host, logger=log)
- ##############################################
- ################ RPC Methods #################
- ##############################################
+ # RPC Methods
@event_handler("eventgen_server", "server_status", handler_type=BROADCAST, reliable_delivery=False)
def event_handler_server_status(self, payload):
@@ -188,7 +189,7 @@ def bundle(self, target, data):
except Exception as e:
self.log.exception(e)
return "500", "Exception: {}".format(e.message)
-
+
@rpc
def setup(self, target, data):
try:
@@ -210,7 +211,7 @@ def get_volume(self, target):
except Exception as e:
self.log.exception(e)
return "500", "Exception: {}".format(e.message)
-
+
@rpc
def set_volume(self, target, data):
try:
@@ -238,10 +239,7 @@ def reset(self, target):
self.log.exception(e)
return '500', "Exception: {}".format(e.message)
-
- ##############################################
- ################ HTTP Methods ################
- ##############################################
+ # HTTP Methods
@http('GET', '/')
def root_page(self, request):
@@ -439,15 +437,13 @@ def http_set_volume_target(self, request, target="all"):
def http_reset(self, request):
return self.reset(target="all")
- ##############################################
- ############### Helper Methods ###############
- ##############################################
+ # Helper Methods
def receive_status(self, data):
if data['server_name'] and data['server_status']:
self.server_status[data['server_name']] = data['server_status']
rec_time = time.time()
- self.log.info("receive {}'s status, update the status at time:{}".format(data['server_name'],rec_time))
+ self.log.info("receive {}'s status, update the status at time:{}".format(data['server_name'], rec_time))
self.server_status['time'] = rec_time
def receive_conf(self, data):
@@ -461,14 +457,15 @@ def receive_volume(self, data):
def process_server_status(self, current_time, num_retries=15, delay=0.3):
current_server_vhosts = self.get_current_server_vhosts()
server_time = self.server_status['time'] if 'time' in self.server_status else 0
- server_vhost_len = len(self.server_status) if 'time' not in self.server_status else len(self.server_status)-1
+ server_vhost_len = len(self.server_status) if 'time' not in self.server_status else len(self.server_status) - 1
if current_server_vhosts:
for i in range(num_retries):
if server_vhost_len != len(current_server_vhosts) or server_time < current_time:
time.sleep(delay)
current_server_vhosts = self.get_current_server_vhosts()
server_time = self.server_status['time'] if 'time' in self.server_status else 0
- server_vhost_len = len(self.server_status) if 'time' not in self.server_status else len(self.server_status)-1
+ server_vhost_len = len(
+ self.server_status) if 'time' not in self.server_status else len(self.server_status) - 1
else:
break
dump_value = self.calculate_throughput(self.server_status)
@@ -515,10 +512,7 @@ def check_vhost(self, vhost_name):
return False
def calculate_throughput(self, data):
- throughput_summary = { 'TOTAL_VOLUME_MB': 0,
- 'TOTAL_COUNT': 0,
- 'THROUGHPUT_VOLUME_KB': 0,
- 'THROUGHPUT_COUNT': 0}
+ throughput_summary = {'TOTAL_VOLUME_MB': 0, 'TOTAL_COUNT': 0, 'THROUGHPUT_VOLUME_KB': 0, 'THROUGHPUT_COUNT': 0}
for server_name, server_status in data.items():
if server_name != 'time' and 'THROUGHPUT_STATUS' in server_status:
server_throughput = server_status['THROUGHPUT_STATUS']
diff --git a/splunk_eventgen/eventgen_nameko_dependency.py b/splunk_eventgen/eventgen_nameko_dependency.py
index a22577c9..6bbcd54e 100644
--- a/splunk_eventgen/eventgen_nameko_dependency.py
+++ b/splunk_eventgen/eventgen_nameko_dependency.py
@@ -1,9 +1,11 @@
-from nameko.extensions import DependencyProvider
-import eventgen_core
-import logging
import argparse
-import sys
+import logging
import os
+import sys
+
+import eventgen_core
+from nameko.extensions import DependencyProvider
+
FILE_PATH = os.path.dirname(os.path.realpath(__file__))
CUSTOM_CONFIG_PATH = os.path.realpath(os.path.join(FILE_PATH, "default", "eventgen_wsgi.conf"))
@@ -12,6 +14,7 @@
# eventgen_nameko_dependency: error: unrecognized arguments: --role master --config server_conf.yml
sys.argv = [sys.argv.pop(0)]
+
def create_args():
parser = argparse.ArgumentParser(prog="eventgen_nameko_dependency")
args = parser.parse_args()
@@ -38,6 +41,7 @@ def create_args():
args.modinput_mode = False
return args
+
class EventgenDependency(DependencyProvider):
arguments = create_args()
diff --git a/splunk_eventgen/eventgen_nameko_server.py b/splunk_eventgen/eventgen_nameko_server.py
index 4bb89e50..cdfe2f35 100644
--- a/splunk_eventgen/eventgen_nameko_server.py
+++ b/splunk_eventgen/eventgen_nameko_server.py
@@ -1,21 +1,23 @@
-from nameko.rpc import rpc
-from nameko.web.handlers import http
-from nameko.events import EventDispatcher, event_handler, BROADCAST
-from pyrabbit.api import Client
import atexit
import ConfigParser
-import yaml
+import glob
import json
+import logging
import os
+import shutil
import socket
-import time
-import requests
-import glob
import tarfile
+import time
import zipfile
-import shutil
+
+import requests
+import yaml
+from pyrabbit.api import Client
+
import eventgen_nameko_dependency
-import logging
+from nameko.events import BROADCAST, EventDispatcher, event_handler
+from nameko.rpc import rpc
+from nameko.web.handlers import http
FILE_PATH = os.path.dirname(os.path.realpath(__file__))
EVENTGEN_DIR = os.path.realpath(os.path.join(FILE_PATH, ".."))
@@ -27,7 +29,6 @@ def get_eventgen_name_from_conf():
with open(os.path.abspath(os.path.join(FILE_PATH, "server_conf.yml"))) as config_yml:
loaded_yml = yaml.load(config_yml)
return loaded_yml['EVENTGEN_NAME'] if 'EVENTGEN_NAME' in loaded_yml else socket.gethostname()
- return None
def exit_handler(client, hostname, logger):
@@ -53,8 +54,7 @@ class EventgenServer(object):
config["AMQP_PASS"] = osvars.get("EVENTGEN_AMQP_PASS", "guest")
pyrabbit_cl = Client('{0}:{1}'.format(config['AMQP_HOST'], config['AMQP_WEBPORT']),
- '{0}'.format(config['AMQP_USER']),
- '{0}'.format(config['AMQP_PASS']))
+ '{0}'.format(config['AMQP_USER']), '{0}'.format(config['AMQP_PASS']))
pyrabbit_cl.create_vhost(host)
log.info("Vhost set to {}".format(host))
@@ -85,7 +85,7 @@ def get_status(self):
if self.eventgen_dependency.eventgen.check_running():
# running
status = 1
- elif self.eventgen_dependency.eventgen.completed == True:
+ elif self.eventgen_dependency.eventgen.completed is True:
# all samples completed and stop
status = 2
else:
@@ -96,9 +96,10 @@ def get_status(self):
res["CONFIGURED"] = self.eventgen_dependency.configured
res["CONFIG_FILE"] = self.eventgen_dependency.configfile
res["TOTAL_VOLUME"] = self.total_volume
- res["QUEUE_STATUS"] = {'SAMPLE_QUEUE': {'UNFINISHED_TASK': 'N/A', 'QUEUE_LENGTH': 'N/A'},
- 'OUTPUT_QUEUE': {'UNFINISHED_TASK': 'N/A', 'QUEUE_LENGTH': 'N/A'},
- 'WORKER_QUEUE': {'UNFINISHED_TASK': 'N/A', 'QUEUE_LENGTH': 'N/A'}}
+ res["QUEUE_STATUS"] = {
+ 'SAMPLE_QUEUE': {'UNFINISHED_TASK': 'N/A', 'QUEUE_LENGTH': 'N/A'}, 'OUTPUT_QUEUE': {
+ 'UNFINISHED_TASK': 'N/A', 'QUEUE_LENGTH': 'N/A'}, 'WORKER_QUEUE': {
+ 'UNFINISHED_TASK': 'N/A', 'QUEUE_LENGTH': 'N/A'}}
res['THROUGHPUT_STATUS'] = self.get_throughput()
if hasattr(self.eventgen_dependency.eventgen, "sampleQueue"):
res["QUEUE_STATUS"]['SAMPLE_QUEUE'][
@@ -114,9 +115,7 @@ def get_status(self):
res["QUEUE_STATUS"]['WORKER_QUEUE']['QUEUE_LENGTH'] = self.eventgen_dependency.eventgen.workerQueue.qsize()
return res
- ##############################################
- ############### Real Methods #################
- ##############################################
+ # Real Methods
def index(self):
self.log.info("index method called")
@@ -139,14 +138,8 @@ def index(self):
sample_queue_status = status["QUEUE_STATUS"]["SAMPLE_QUEUE"]
output_queue_status = status["QUEUE_STATUS"]["OUTPUT_QUEUE"]
- return home_page.format(host,
- eventgen_status,
- configured,
- config_file,
- total_volume,
- worker_queue_status,
- sample_queue_status,
- output_queue_status)
+ return home_page.format(host, eventgen_status, configured, config_file, total_volume, worker_queue_status,
+ sample_queue_status, output_queue_status)
def status(self):
self.log.info('Status method called.')
@@ -344,28 +337,18 @@ def setup(self, data):
new_key = bool(data.get("new_key", True))
def create_new_hec_key(hostname):
- requests.post("https://{0}:{1}/servicesNS/admin/splunk_httpinput/data/inputs/http/http".format(
- hostname, mgmt_port),
- auth=("admin", password),
- data={"disabled": "0"},
- verify=False)
+ requests.post(
+ "https://{0}:{1}/servicesNS/admin/splunk_httpinput/data/inputs/http/http".format(
+ hostname, mgmt_port), auth=("admin", password), data={"disabled": "0"}, verify=False)
requests.delete(
- "https://{0}:{1}/servicesNS/admin/splunk_httpinput/data/inputs/http/{2}".format(
- hostname, mgmt_port,key_name),
- verify=False,
- auth=("admin", password)
- )
+ "https://{0}:{1}/servicesNS/admin/splunk_httpinput/data/inputs/http/{2}".format(
+ hostname, mgmt_port, key_name), verify=False, auth=("admin", password))
requests.post(
- "https://{0}:{1}/servicesNS/admin/splunk_httpinput/data/inputs/http?output_mode=json".format(
- hostname, mgmt_port),
- verify=False,
- auth=("admin", password),
- data={"name": key_name})
+ "https://{0}:{1}/servicesNS/admin/splunk_httpinput/data/inputs/http?output_mode=json".format(
+ hostname, mgmt_port), verify=False, auth=("admin", password), data={"name": key_name})
r = requests.post(
- "https://{0}:{1}/servicesNS/admin/splunk_httpinput/data/inputs/http/{2}?output_mode=json".format(
- hostname, mgmt_port, key_name),
- verify=False,
- auth=("admin", password))
+ "https://{0}:{1}/servicesNS/admin/splunk_httpinput/data/inputs/http/{2}?output_mode=json".format(
+ hostname, mgmt_port, key_name), verify=False, auth=("admin", password))
return str(json.loads(r.text)["entry"][0]["content"]["token"])
self.discovered_servers = []
@@ -375,10 +358,9 @@ def create_new_hec_key(hostname):
if new_key:
key = create_new_hec_key(formatted_hostname)
- self.discovered_servers.append({"protocol": str(protocol),
- "address": str(formatted_hostname),
- "port": str(hec_port),
- "key": str(key)})
+ self.discovered_servers.append({
+ "protocol": str(protocol), "address": str(formatted_hostname), "port": str(hec_port), "key":
+ str(key)})
except socket.gaierror:
continue
@@ -389,10 +371,9 @@ def create_new_hec_key(hostname):
if new_key:
key = create_new_hec_key(formatted_hostname)
- self.discovered_servers.append({"protocol": str(protocol),
- "address": str(formatted_hostname),
- "port": str(hec_port),
- "key": str(key)})
+ self.discovered_servers.append({
+ "protocol": str(protocol), "address": str(formatted_hostname), "port": str(hec_port), "key":
+ str(key)})
counter += 1
except socket.gaierror:
break
@@ -477,9 +458,7 @@ def reset(self):
self.log.exception(e)
return '500', "Exception: {}".format(e.message)
- ##############################################
- ############ Event Handler Methods ###########
- ##############################################
+ # Event Handler Methods
@event_handler("eventgen_controller", "all_index", handler_type=BROADCAST, reliable_delivery=False)
def event_handler_all_index(self, payload):
@@ -602,9 +581,7 @@ def event_handler_set_volume(self, payload):
def event_handler_reset(self, payload):
return self.reset()
- ##############################################
- ################ HTTP Methods ################
- ##############################################
+ # HTTP Methods
@http('GET', '/')
def http_root(self, request):
@@ -696,9 +673,7 @@ def http_set_volume(self, request):
def http_reset(self, request):
return json.dumps(self.reset())
- ##############################################
- ################ Helper Methods ##############
- ##############################################
+ # Helper Methods
def parse_eventgen_conf(self, path):
config = ConfigParser.ConfigParser()
@@ -759,10 +734,7 @@ def get_data_volumes(self, config):
def get_throughput(self):
self.log.debug("Getting throughput ...")
- empty_throughput = {'TOTAL_VOLUME_MB': 0,
- 'TOTAL_COUNT': 0,
- 'THROUGHPUT_VOLUME_KB': 0,
- 'THROUGHPUT_COUNT': 0}
+ empty_throughput = {'TOTAL_VOLUME_MB': 0, 'TOTAL_COUNT': 0, 'THROUGHPUT_VOLUME_KB': 0, 'THROUGHPUT_COUNT': 0}
if hasattr(self.eventgen_dependency.eventgen, 'output_counters'):
total_volume = 0
total_count = 0
@@ -773,10 +745,9 @@ def get_throughput(self):
total_count += output_counter.total_output_count
throughput_volume += output_counter.throughput_volume
throughput_count += output_counter.throughput_count
- return {'TOTAL_VOLUME_MB': total_volume / (1024*1024),
- 'TOTAL_COUNT': total_count,
- 'THROUGHPUT_VOLUME_KB': throughput_volume / (1024),
- 'THROUGHPUT_COUNT': throughput_count}
+ return {
+ 'TOTAL_VOLUME_MB': total_volume / (1024 * 1024), 'TOTAL_COUNT': total_count, 'THROUGHPUT_VOLUME_KB':
+ throughput_volume / (1024), 'THROUGHPUT_COUNT': throughput_count}
else:
self.log.debug("return empty throughput because of output_counters not found.")
- return empty_throughput
\ No newline at end of file
+ return empty_throughput
diff --git a/splunk_eventgen/identitygen.py b/splunk_eventgen/identitygen.py
index a0c29939..f95a1047 100644
--- a/splunk_eventgen/identitygen.py
+++ b/splunk_eventgen/identitygen.py
@@ -4,115 +4,135 @@
import time
from string import ascii_uppercase
-BASE_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
+BASE_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
+
class identityGenerator(object):
- '''
- Generates csv file with the following values
- '''
- CATEGORIES = ["cardholder","cardholder|pci","officer|pci","intern","default","default","default","default","sox","pci","officer","","","","","","","","","",""]
- LOCATION = [["San Francisco","USA","americas","37.3382N","121.6663W"],["San Jose","USA","americas","37.78N","122.41W"]]
- EMAIL_DOMAIN = "@splunk.com"
- PRIORITIES = ["low","low","low","low","low","low","medium","medium","high","critical"]
- def __init__(self):
- try:
- self.last = [i.split()[0] for i in open("%s/samples/dist.all.last"%BASE_PATH,"rb").readlines()]
- except IOError as e:
- self.last = [(''.join(random.choice(ascii_uppercase) for i in xrange(random.randint(4,12)))) for i in xrange(100)]
- try:
- self.female_first = [i.split()[0] for i in open("%s/samples/dist.female.first"%BASE_PATH,"rb").readlines()]
- except IOError as e:
- self.female_first = [(''.join(random.choice(ascii_uppercase) for i in xrange(random.randint(4,12)))) for i in xrange(100)]
- try:
- self.male_first = [i.split()[0] for i in open("%s/samples/dist.male.first"%BASE_PATH,"rb").readlines()]
- except IOError as e:
- self.male_first = [(''.join(random.choice(ascii_uppercase) for i in xrange(random.randint(4,12)))) for i in xrange(100)]
+ """
+ Generates csv file with the following values
+ """
+ CATEGORIES = [
+ "cardholder", "cardholder|pci", "officer|pci", "intern", "default", "default", "default", "default", "sox",
+ "pci", "officer", "", "", "", "", "", "", "", "", "", ""]
+ LOCATION = [["San Francisco", "USA", "americas", "37.3382N", "121.6663W"],
+ ["San Jose", "USA", "americas", "37.78N", "122.41W"]]
+ EMAIL_DOMAIN = "@splunk.com"
+ PRIORITIES = ["low", "low", "low", "low", "low", "low", "medium", "medium", "high", "critical"]
+
+ def __init__(self):
+ try:
+ self.last = [i.split()[0] for i in open("%s/samples/dist.all.last" % BASE_PATH, "rb").readlines()]
+ except IOError:
+ self.last = [
+ (''.join(random.choice(ascii_uppercase) for i in xrange(random.randint(4, 12)))) for i in xrange(100)]
+ try:
+ self.female_first = [
+ i.split()[0] for i in open("%s/samples/dist.female.first" % BASE_PATH, "rb").readlines()]
+ except IOError:
+ self.female_first = [
+ (''.join(random.choice(ascii_uppercase) for i in xrange(random.randint(4, 12)))) for i in xrange(100)]
+ try:
+ self.male_first = [i.split()[0] for i in open("%s/samples/dist.male.first" % BASE_PATH, "rb").readlines()]
+ except IOError:
+ self.male_first = [
+ (''.join(random.choice(ascii_uppercase) for i in xrange(random.randint(4, 12)))) for i in xrange(100)]
+
+ def generate(self, count):
+ self.identities = []
+ usernames = dict()
+ username = ""
+ len_last = len(self.last)
+ len_male_first = len(self.male_first)
+ len_female_first = len(self.female_first)
+ for i in xrange(count):
+ gender = random.choice(["m", "f"])
+ last_name = self.last[int(random.triangular(0, len_last, 0))]
+ if gender == "m":
+ first_name = self.male_first[int(random.triangular(0, len_male_first, 0))]
+ else:
+ first_name = self.female_first[int(random.triangular(0, len_female_first, 0))]
+ category = random.choice(self.CATEGORIES)
+ priority = random.choice(self.PRIORITIES)
+ startDate = time.strftime("%m/%d/%Y", time.localtime(time.time() - random.randint(2592000, 77760000))
+ ) # random start date between 30 days ago to 900 days ago
+ (work_city, work_country, bunit, work_lat, work_long) = random.choice(self.LOCATION)
+ identity = {
+ "first_name": first_name, "last_name": last_name, "work_city": work_city, "work_country": work_country,
+ "bunit": bunit, "work_lat": work_lat, "work_long": work_long, "priority": priority, "category":
+ category, "startDate": startDate}
+ base_username = identity["first_name"] + identity["last_name"]
+ if base_username in usernames:
+ tmp_val = 0
+ while username + str(tmp_val) in usernames[base_username]:
+ tmp_val += 1
+ username = base_username + str(tmp_val)
+ usernames[base_username].append(username)
+ else:
+ username = base_username
+ usernames[username] = list()
+ identity["username"] = username
+ identity["ip"] = self.int2InternalIP(i)
+ self.identities.append(identity)
- def generate(self, count):
- self.identities = []
- usernames = dict()
- len_last = len(self.last)
- len_male_first = len(self.male_first)
- len_female_first = len(self.female_first)
- prev_time = time.time()
- for i in xrange(count):
- gender = random.choice(["m","f"])
- last_name = self.last[int(random.triangular(0,len_last,0))]
- if gender == "m":
- first_name = self.male_first[int(random.triangular(0,len_male_first,0))]
- else:
- first_name = self.female_first[int(random.triangular(0,len_female_first,0))]
- category = random.choice(self.CATEGORIES)
- priority = random.choice(self.PRIORITIES)
- startDate = time.strftime("%m/%d/%Y", time.localtime(time.time()-random.randint(2592000,77760000))) # random start date between 30 days ago to 900 days ago
- (work_city, work_country, bunit, work_lat, work_long)= random.choice(self.LOCATION)
- identity = {"first_name":first_name,"last_name":last_name,"work_city":work_city,"work_country":work_country,"bunit":bunit,"work_lat":work_lat,"work_long":work_long,"priority":priority,"category":category,"startDate":startDate}
- base_username = identity["first_name"] + identity["last_name"]
- t = time.time()
- if base_username in usernames:
- tmp_val = 0
- while username + str(tmp_val) in usernames[base_username]:
- tmp_val += 1
- username = base_username + str(tmp_val)
- usernames[base_username].append(username)
- else:
- username = base_username
- usernames[username] = list()
- identity["username"] = username
- identity["ip"] = self.int2InternalIP(i)
- self.identities.append(identity)
-
+ def int2InternalIP(self, i):
+ return "10.%s.%s.%s" % (str(int(i / 65536)), str(int(i / 256) % 256), str(i % 256))
- def int2InternalIP(self,i):
- return "10.%s.%s.%s" % (str(int(i/65536)), str(int(i/256)%256), str(i%256))
+ def setLocations(self, new_locations):
+ for location in new_locations:
+ if len(location) != 5:
+ raise ValueError
+ self.CATEGORIES = new_locations
- def setLocations(self,new_locations):
- for location in new_locations:
- if len(location)!=5:
- raise ValueError
- self.CATEGORIES = new_locations
+ def setCategories(self, new_categories):
+ self.CATEGORIES = new_categories
- def setCategories(self,new_categories):
- self.CATEGORIES = new_categories
+ def setEmail(self, new_email):
+ if "@" in new_email:
+ self.EMAIL_DOMAIN = new_email
+ else:
+ raise ValueError
- def setEmail(self,new_email):
- if "@" in new_email:
- self.EMAIL_DOMAIN = new_email
- else:
- raise ValueError
+ def getFile(self, count=0, filename="../default", fields=["username", "first_name", "last_name"], fieldnames=[
+ "username", "first_name", "last_name"]):
+ """
+ Returns a rest endpoint to download a csv file
+ """
+ if count == 0:
+ with open(filename, "wb") as lookupFile:
+ file = csv.writer(lookupFile)
+ file.writerow(fieldnames)
+ for identity in self.identities:
+ row = []
+ for field in fields:
+ try:
+ row.append(identity[field])
+ except KeyError:
+ row.append("")
+ file.writerow(row)
+ else:
+ with open(filename, "wb") as lookupFile:
+ file = csv.writer(lookupFile)
+ file.writerow(fieldnames)
+ for i in xrange(min(count + 1, len(self.identities))): # + 1 to account for the header
+ row = []
+ identity = self.identities[i]
+ for field in fields:
+ try:
+ row.append(identity[field])
+ except KeyError:
+ row.append("")
+ file.writerow(row)
+ return open(filename, "rb")
- def getFile(self,count=0,filename="../default",fields=["username","first_name","last_name"],fieldnames=["username","first_name","last_name"]):
- 'Returns a rest endpoint to download a csv file'
- if count == 0:
- with open(filename,"wb") as lookupFile:
- file = csv.writer(lookupFile)
- file.writerow(fieldnames)
- for identity in self.identities:
- row = []
- for field in fields:
- try:
- row.append(identity[field])
- except KeyError:
- row.append("")
- file.writerow(row)
- else:
- with open(filename,"wb") as lookupFile:
- file = csv.writer(lookupFile)
- file.writerow(fieldnames)
- for i in xrange(min(count+1,len(identities))): # + 1 to account for the header
- row = []
- identity = identities[i]
- for field in fields:
- try:
- row.append(identity[field])
- except KeyError:
- row.append("")
- file.writerow(row)
- return open(filename,"rb")
if __name__ == "__main__":
- identityGenerator = identityGenerator()
- identityGenerator.generate(300000)
- identityGenerator.getFile(filename="identities.csv",
- fields=["username","prefix","username","first_name","last_name","suffix","email","phone","phone2","managedBy","priority","bunit","category","watchlist","startDate","endDate","work_city","work_country","work_lat","work_long"],
- fieldnames = ["identity","prefix","nick","first","last","suffix","email","phone","phone2","managedBy","priority","bunit","category","watchlist","startDate","endDate","work_city","work_country","work_lat","work_long"])
\ No newline at end of file
+ identityGenerator = identityGenerator()
+ identityGenerator.generate(300000)
+ identityGenerator.getFile(
+ filename="identities.csv", fields=[
+ "username", "prefix", "username", "first_name", "last_name", "suffix", "email", "phone", "phone2",
+ "managedBy", "priority", "bunit", "category", "watchlist", "startDate", "endDate", "work_city",
+ "work_country", "work_lat", "work_long"], fieldnames=[
+ "identity", "prefix", "nick", "first", "last", "suffix", "email", "phone", "phone2", "managedBy",
+ "priority", "bunit", "category", "watchlist", "startDate", "endDate", "work_city", "work_country",
+ "work_lat", "work_long"])
diff --git a/splunk_eventgen/lib/eventgenconfig.py b/splunk_eventgen/lib/eventgenconfig.py
index 161fca6b..d9382bfc 100644
--- a/splunk_eventgen/lib/eventgenconfig.py
+++ b/splunk_eventgen/lib/eventgenconfig.py
@@ -1,17 +1,20 @@
from __future__ import division
-from ConfigParser import ConfigParser
-import os
+
import datetime
-import re
-import logging, logging.handlers
import json
+import logging
+import logging.handlers
+import os
import pprint
+import random
+import re
+import types
+import urllib
+from ConfigParser import ConfigParser
+
+from eventgenexceptions import FailedLoadingPlugin, PluginNotLoaded
from eventgensamples import Sample
from eventgentoken import Token
-from eventgenexceptions import PluginNotLoaded, FailedLoadingPlugin
-import urllib
-import types
-import random
# 4/21/14 CS Adding a defined constant whether we're running in standalone mode or not
# Standalone mode is when we know we're Splunk embedded but we want to force
@@ -50,11 +53,11 @@ class Config(object):
sessionKey = None
grandparentdir = None
greatgrandparentdir = None
- samples = [ ]
+ samples = []
sampleDir = None
outputWorkers = None
generatorWorkers = None
- sampleTimers = [ ]
+ sampleTimers = []
# Config file options. We do not define defaults here, rather we pull them in
# from eventgen.conf.
@@ -65,10 +68,10 @@ class Config(object):
disabled = None
blacklist = ".*\.part"
- __generatorworkers = [ ]
- __outputworkers = [ ]
- outputPlugins = { }
- plugins = { }
+ __generatorworkers = []
+ __outputworkers = []
+ outputPlugins = {}
+ plugins = {}
outputQueue = None
generatorQueue = None
args = None
@@ -82,30 +85,32 @@ class Config(object):
'minuteOfHourRate', 'timezone', 'dayOfMonthRate', 'monthOfYearRate', 'perDayVolume',
'outputWorkers', 'generator', 'rater', 'generatorWorkers', 'timeField', 'sampleDir', 'threading',
'profiler', 'maxIntervalsBeforeFlush', 'maxQueueLength', 'splunkMethod', 'splunkPort',
- 'verbosity', 'useOutputQueue', 'seed','end', 'autotimestamps', 'autotimestamp', 'httpeventWaitResponse', 'outputCounter', 'sequentialTimestamp']
+ 'verbosity', 'useOutputQueue', 'seed','end', 'autotimestamps', 'autotimestamp', 'httpeventWaitResponse',
+ 'outputCounter', 'sequentialTimestamp', 'extendIndexes']
_validTokenTypes = {'token': 0, 'replacementType': 1, 'replacement': 2}
_validHostTokens = {'token': 0, 'replacement': 1}
- _validReplacementTypes = ['static', 'timestamp', 'replaytimestamp', 'random', 'rated', 'file', 'mvfile', 'seqfile', 'integerid']
- validOutputModes = [ ]
+ _validReplacementTypes = [
+ 'static', 'timestamp', 'replaytimestamp', 'random', 'rated', 'file', 'mvfile', 'seqfile', 'integerid']
+ validOutputModes = []
_intSettings = ['interval', 'outputWorkers', 'generatorWorkers', 'maxIntervalsBeforeFlush', 'maxQueueLength']
_floatSettings = ['randomizeCount', 'delay', 'timeMultiple']
- _boolSettings = ['disabled', 'randomizeEvents', 'bundlelines', 'profiler', 'useOutputQueue', 'autotimestamp', 'httpeventWaitResponse', 'outputCounter', 'sequentialTimestamp']
- _jsonSettings = ['hourOfDayRate', 'dayOfWeekRate', 'minuteOfHourRate', 'dayOfMonthRate', 'monthOfYearRate', 'autotimestamps']
- _defaultableSettings = ['disabled', 'spoolDir', 'spoolFile', 'breaker', 'sampletype', 'interval', 'delay',
- 'count', 'bundlelines', 'earliest', 'latest', 'hourOfDayRate', 'dayOfWeekRate',
- 'randomizeCount', 'randomizeEvents', 'outputMode', 'fileMaxBytes', 'fileBackupFiles',
- 'splunkHost', 'splunkPort', 'splunkMethod', 'index', 'source', 'sourcetype', 'host', 'hostRegex',
- 'projectID', 'accessToken', 'mode', 'minuteOfHourRate', 'timeMultiple', 'dayOfMonthRate',
- 'monthOfYearRate', 'perDayVolume', 'sessionKey', 'generator', 'rater', 'timeField', 'maxQueueLength',
- 'maxIntervalsBeforeFlush', 'autotimestamp']
- _complexSettings = { 'sampletype': ['raw', 'csv'],
- 'mode': ['sample', 'replay'],
- 'threading': ['thread', 'process']}
+ _boolSettings = [
+ 'disabled', 'randomizeEvents', 'bundlelines', 'profiler', 'useOutputQueue', 'autotimestamp',
+ 'httpeventWaitResponse', 'outputCounter', 'sequentialTimestamp']
+ _jsonSettings = [
+ 'hourOfDayRate', 'dayOfWeekRate', 'minuteOfHourRate', 'dayOfMonthRate', 'monthOfYearRate', 'autotimestamps']
+ _defaultableSettings = [
+ 'disabled', 'spoolDir', 'spoolFile', 'breaker', 'sampletype', 'interval', 'delay', 'count', 'bundlelines',
+ 'earliest', 'latest', 'hourOfDayRate', 'dayOfWeekRate', 'randomizeCount', 'randomizeEvents', 'outputMode',
+ 'fileMaxBytes', 'fileBackupFiles', 'splunkHost', 'splunkPort', 'splunkMethod', 'index', 'source', 'sourcetype',
+ 'host', 'hostRegex', 'projectID', 'accessToken', 'mode', 'minuteOfHourRate', 'timeMultiple', 'dayOfMonthRate',
+ 'monthOfYearRate', 'perDayVolume', 'sessionKey', 'generator', 'rater', 'timeField', 'maxQueueLength',
+ 'maxIntervalsBeforeFlush', 'autotimestamp']
+ _complexSettings = {'sampletype': ['raw', 'csv'], 'mode': ['sample', 'replay'], 'threading': ['thread', 'process']}
def __init__(self, configfile=None, sample=None, override_outputter=False, override_count=False,
- override_interval=False, override_backfill=False, override_end=False,
- threading="thread", override_generators=None, override_outputqueue=False,
- profiler=False, verbosity=40):
+ override_interval=False, override_backfill=False, override_end=False, threading="thread",
+ override_generators=None, override_outputqueue=False, profiler=False, verbosity=40):
"""Setup Config object. Sets up Logging and path related variables."""
# Rebind the internal datastore of the class to an Instance variable
self.__dict__ = self.__sharedState
@@ -144,18 +149,18 @@ def __init__(self, configfile=None, sample=None, override_outputter=False, overr
self.stopping = False
- #self.copyLock = threading.Lock() if self.threading == 'thread' else multiprocessing.Lock()
+ # self.copyLock = threading.Lock() if self.threading == 'thread' else multiprocessing.Lock()
self._firsttime = False
def __str__(self):
"""Only used for debugging, outputs a pretty printed representation of our Config"""
# Filter items from config we don't want to pretty print
- filter_list = [ 'samples', 'sampleTimers', '__generatorworkers', '__outputworkers' ]
+ filter_list = ['samples', 'sampleTimers', '__generatorworkers', '__outputworkers']
# Eliminate recursive going back to parent
- temp = dict([ (key, value) for (key, value) in self.__dict__.items() if key not in filter_list ])
+ temp = dict([(key, value) for (key, value) in self.__dict__.items() if key not in filter_list])
- return 'Config:'+pprint.pformat(temp)+'\nSamples:\n'+pprint.pformat(self.samples)
+ return 'Config:' + pprint.pformat(temp) + '\nSamples:\n' + pprint.pformat(self.samples)
# loggers can't be pickled due to the lock object, remove them before we try to pickle anything.
def __getstate__(self):
@@ -173,14 +178,13 @@ def _setup_logging(self):
def getPlugin(self, name, s=None):
"""Return a reference to a Python object (not an instance) referenced by passed name"""
-
'''
APPPERF-263:
make sure we look in __outputPlugins as well. For some reason we
keep 2 separate dicts of plugins.
'''
- plugintype=name.split(".")[0]
- if not name in self.plugins and not name in self.outputPlugins:
+ plugintype = name.split(".")[0]
+ if name not in self.plugins and name not in self.outputPlugins:
# 2/1/15 CS If we haven't already seen the plugin, try to load it
# Note, this will only work for plugins which do not specify config validation
# parameters. If they do, configs may not validate for user provided plugins.
@@ -189,14 +193,14 @@ def getPlugin(self, name, s=None):
plugin = getattr(s, plugintype)
else:
plugin = getattr(s, 'outputMode')
- if plugin != None:
- self.logger.debug("Attempting to dynamically load plugintype '%s' named '%s' for sample '%s'"
- % (plugintype, plugin, s.name))
+ if plugin is not None:
+ self.logger.debug("Attempting to dynamically load plugintype '%s' named '%s' for sample '%s'" %
+ (plugintype, plugin, s.name))
bindir = os.path.join(s.sampleDir, os.pardir, 'bin')
libdir = os.path.join(s.sampleDir, os.pardir, 'lib')
plugindir = os.path.join(libdir, 'plugins', plugintype)
- targetplugin = PluginNotLoaded(bindir=bindir, libdir=libdir,
- plugindir=plugindir, name=plugin, type=plugintype)
+ targetplugin = PluginNotLoaded(bindir=bindir, libdir=libdir, plugindir=plugindir, name=plugin,
+ type=plugintype)
if targetplugin.name not in self.extraplugins:
self.extraplugins.append(targetplugin.name)
raise targetplugin
@@ -204,7 +208,7 @@ def getPlugin(self, name, s=None):
raise FailedLoadingPlugin(name=plugin)
# APPPERF-263: consult both __outputPlugins and __plugins
- if not name in self.plugins and not name in self.outputPlugins:
+ if name not in self.plugins and name not in self.outputPlugins:
raise KeyError('Plugin ' + name + ' not found')
# return in order of precedence: __plugins, __outputPlugins, None
@@ -218,7 +222,7 @@ def makeSplunkEmbedded(self, sessionKey):
def getSplunkUrl(self, s):
"""
- Get Splunk URL. If we're embedded in Splunk, get it from Splunk's Python libraries, otherwise get it from config.
+ If we're embedded in Splunk, get it from Splunk's Python libraries, otherwise get it from config.
Returns a tuple of ( splunkUrl, splunkMethod, splunkHost, splunkPort )
"""
@@ -233,11 +237,14 @@ def getSplunkUrl(self, s):
except:
import traceback
trace = traceback.format_exc()
- self.logger.error('Error parsing host from splunk.auth.splunk.getLocalServerInfo() for sample %s. Stacktrace: %s' % (s.name, trace))
- raise ValueError('Error parsing host from splunk.auth.splunk.getLocalServerInfo() for sample %s' % s.name)
+ self.logger.error(
+ 'Error parsing host from splunk.auth.splunk.getLocalServerInfo() for sample %s. Stacktrace: %s' %
+ (s.name, trace))
+ raise ValueError(
+ 'Error parsing host from splunk.auth.splunk.getLocalServerInfo() for sample %s' % s.name)
else:
# splunkMethod and splunkPort are defaulted so only check for splunkHost
- if s.splunkHost == None:
+ if s.splunkHost is None:
self.logger.error("Splunk URL Requested but splunkHost not set for sample '%s'" % s.name)
raise ValueError("Splunk URL Requested but splunkHost not set for sample '%s'" % s.name)
@@ -246,7 +253,8 @@ def getSplunkUrl(self, s):
splunkHost = s.splunkHost
splunkPort = s.splunkPort
- self.logger.debug("Getting Splunk URL: %s Method: %s Host: %s Port: %s" % (splunkUrl, splunkMethod, splunkHost, splunkPort))
+ self.logger.debug(
+ "Getting Splunk URL: %s Method: %s Host: %s Port: %s" % (splunkUrl, splunkMethod, splunkHost, splunkPort))
return (splunkUrl, splunkMethod, splunkHost, splunkPort)
def parse(self):
@@ -267,8 +275,8 @@ def parse(self):
if 'default' in self._confDict:
del self._confDict['default']
- tempsamples = [ ]
- tempsamples2 = [ ]
+ tempsamples = []
+ tempsamples2 = []
stanza_map = {}
stanza_list = []
@@ -322,7 +330,8 @@ def parse(self):
if 'token.{}.token'.format(i) in self._confDict[global_stanza]:
token = self._confDict[global_stanza].get('token.{}.token'.format(i))
replacement = self._confDict[global_stanza].get('token.{}.replacement'.format(i))
- replacementType = self._confDict[global_stanza].get('token.{}.replacementType'.format(i))
+ replacementType = self._confDict[global_stanza].get(
+ 'token.{}.replacementType'.format(i))
last_token_number += 1
if token:
@@ -343,9 +352,9 @@ def parse(self):
break
keys = settings.keys()
- for k,v in self._confDict[global_stanza].items():
+ for k, v in self._confDict[global_stanza].items():
if 'token' not in k and k not in keys:
- kv_pair_items.append((k,v))
+ kv_pair_items.append((k, v))
for key, value in kv_pair_items:
oldvalue = value
@@ -359,7 +368,7 @@ def parse(self):
# Token indices could be out of order, so we must check to
# see whether we have enough items in the list to update the token
# In general this will keep growing the list by whatever length we need
- if(key.find("host.") > -1):
+ if (key.find("host.") > -1):
# self.logger.info("hostToken.{} = {}".format(value[1],oldvalue))
if not isinstance(s.hostToken, Token):
s.hostToken = Token(s)
@@ -368,8 +377,8 @@ def parse(self):
setattr(s.hostToken, value[0], oldvalue)
else:
if len(s.tokens) <= value[0]:
- x = (value[0]+1) - len(s.tokens)
- s.tokens.extend([None for i in xrange(0, x)])
+ x = (value[0] + 1) - len(s.tokens)
+ s.tokens.extend([None for num in xrange(0, x)])
if not isinstance(s.tokens[value[0]], Token):
s.tokens[value[0]] = Token(s)
# logger.info("token[{}].{} = {}".format(value[0],value[1],oldvalue))
@@ -383,42 +392,39 @@ def parse(self):
s._lockedSettings.append(key)
# self.logger.debug("Appending '%s' to locked settings for sample '%s'" % (key, s.name))
-
-
# Validate all the tokens are fully setup, can't do this in _validateSettings
# because they come over multiple lines
# Don't error out at this point, just log it and remove the token and move on
- deleteidx = [ ]
+ deleteidx = []
for i in xrange(0, len(s.tokens)):
t = s.tokens[i]
# If the index doesn't exist at all
- if t == None:
+ if t is None:
self.logger.error("Token at index %s invalid" % i)
# Can't modify list in place while we're looping through it
# so create a list to remove later
deleteidx.append(i)
- elif t.token == None or t.replacementType == None or t.replacement == None:
+ elif t.token is None or t.replacementType is None or t.replacement is None:
self.logger.error("Token at index %s invalid" % i)
deleteidx.append(i)
- newtokens = [ ]
+ newtokens = []
for i in xrange(0, len(s.tokens)):
if i not in deleteidx:
newtokens.append(s.tokens[i])
s.tokens = newtokens
-
# Must have eai:acl key to determine app name which determines where actual files are
- if s.app == None:
+ if s.app is None:
self.logger.error("App not set for sample '%s' in stanza '%s'" % (s.name, stanza))
raise ValueError("App not set for sample '%s' in stanza '%s'" % (s.name, stanza))
# Set defaults for items not included in the config file
for setting in self._defaultableSettings:
- if not hasattr(s, setting) or getattr(s, setting) == None:
+ if not hasattr(s, setting) or getattr(s, setting) is None:
setattr(s, setting, getattr(self, setting, None))
# Append to temporary holding list
if not s.disabled:
- s._priority = len(tempsamples)+1
+ s._priority = len(tempsamples) + 1
tempsamples.append(s)
# 6/22/12 CS Rewriting the config matching code yet again to handling flattening better.
@@ -427,14 +433,15 @@ def parse(self):
# every other match to that one.
for s in tempsamples:
# Now we need to match this up to real files. May generate multiple copies of the sample.
- foundFiles = [ ]
+ foundFiles = []
# 1/5/14 Adding a config setting to override sample directory, primarily so I can put tests in their own
# directories
- if s.sampleDir == None:
+ if s.sampleDir is None:
self.logger.debug("Sample directory not specified in config, setting based on standard")
if self.splunkEmbedded and not STANDALONE:
- s.sampleDir = os.path.normpath(os.path.join(self.grandparentdir, '..', '..', '..', s.app, 'samples'))
+ s.sampleDir = os.path.normpath(
+ os.path.join(self.grandparentdir, '..', '..', '..', s.app, 'samples'))
else:
# 2/1/15 CS Adding support for looking for samples based on the config file specified on
# the command line.
@@ -452,7 +459,8 @@ def parse(self):
if not os.path.exists(s.sampleDir):
newSampleDir = os.path.join(self.grandparentdir, 'samples')
- self.logger.error("Path not found for samples '%s', trying '%s'" % (s.sampleDir, newSampleDir))
+ self.logger.error(
+ "Path not found for samples '%s', trying '%s'" % (s.sampleDir, newSampleDir))
s.sampleDir = newSampleDir
else:
self.logger.debug("Sample directory specified in config, checking for relative")
@@ -485,10 +493,12 @@ def parse(self):
self.maxIntervalsBeforeFlush = 1
s.maxIntervalsBeforeFlush = 1
s.maxQueueLength = s.maxQueueLength or 1
- self.logger.debug("Sample '%s' setting maxQueueLength to '%s' from command line" % (s.name, s.maxQueueLength))
+ self.logger.debug(
+ "Sample '%s' setting maxQueueLength to '%s' from command line" % (s.name, s.maxQueueLength))
if self.override_outputter:
- self.logger.debug("Sample '%s' setting output to '%s' from command line" % (s.name, self.override_outputter))
+ self.logger.debug(
+ "Sample '%s' setting output to '%s' from command line" % (s.name, self.override_outputter))
s.outputMode = self.override_outputter
if self.override_count:
@@ -498,11 +508,13 @@ def parse(self):
s.backfill = None
if self.override_interval:
- self.logger.debug("Overriding interval to '%d' for sample '%s'" % (self.override_interval, s.name))
+ self.logger.debug(
+ "Overriding interval to '%d' for sample '%s'" % (self.override_interval, s.name))
s.interval = self.override_interval
if self.override_backfill:
- self.logger.debug("Overriding backfill to '%s' for sample '%s'" % (self.override_backfill, s.name))
+ self.logger.debug(
+ "Overriding backfill to '%s' for sample '%s'" % (self.override_backfill, s.name))
s.backfill = self.override_backfill.lstrip()
if self.override_end:
@@ -517,7 +529,7 @@ def parse(self):
for token in s.tokens:
if token.replacementType == 'integerid':
try:
- stateFile = open(os.path.join(s.sampleDir, 'state.'+urllib.pathname2url(token.token)), 'rU')
+ stateFile = open(os.path.join(s.sampleDir, 'state.' + urllib.pathname2url(token.token)), 'rU')
token.replacement = stateFile.read()
stateFile.close()
# The file doesn't exist, use the default value in the config
@@ -532,8 +544,9 @@ def parse(self):
self.logger.debug("Matched file {0} with sample name {1}".format(results.group(0), s.name))
samplePath = os.path.join(s.sampleDir, sample)
if os.path.isfile(samplePath):
- self.logger.debug("Found sample file '%s' for app '%s' using config '%s' with priority '%s'; adding to list" \
- % (sample, s.app, s.name, s._priority) )
+ self.logger.debug(
+ "Found sample file '%s' for app '%s' using config '%s' with priority '%s'" %
+ (sample, s.app, s.name, s._priority) + "; adding to list")
foundFiles.append(samplePath)
# If we didn't find any files, log about it
@@ -554,9 +567,9 @@ def parse(self):
# Override with real name
if s.outputMode == 'spool' and s.spoolFile == self.spoolFile:
news.spoolFile = f.split(os.sep)[-1]
- if s.outputMode == 'file' and s.fileName == None and s.spoolFile == self.spoolFile:
+ if s.outputMode == 'file' and s.fileName is None and s.spoolFile == self.spoolFile:
news.fileName = os.path.join(s.spoolDir, f.split(os.sep)[-1])
- elif s.outputMode == 'file' and s.fileName == None and s.spoolFile != None:
+ elif s.outputMode == 'file' and s.fileName is None and s.spoolFile is not None:
news.fileName = os.path.join(s.spoolDir, s.spoolFile)
# Override s.name with file name. Usually they'll match unless we've been a regex
# 6/22/12 CS Save original name for later matching
@@ -568,7 +581,7 @@ def parse(self):
self.logger.info("Sample '%s' for app '%s' is marked disabled." % (news.name, news.app))
# Clear tempsamples, we're going to reuse it
- tempsamples = [ ]
+ tempsamples = []
# We're now going go through the samples and attempt to apply any matches from other stanzas
# This allows us to specify a wildcard at the beginning of the file and get more specific as we go on
@@ -576,25 +589,26 @@ def parse(self):
# Loop through all samples, create a list of the master samples
for s in tempsamples2:
foundHigherPriority = False
- othermatches = [ ]
+ othermatches = []
# If we're an exact match, don't go looking for higher priorities
if not s.name == s._origName:
for matchs in tempsamples2:
if matchs.filePath == s.filePath and s._origName != matchs._origName:
# We have a match, now determine if we're higher priority or not
- # If this is a longer pattern or our match is an exact match
- # then we're a higher priority match
+ # If this is a longer pattern or our match is an exact match
+ # then we're a higher priority match
if len(matchs._origName) > len(s._origName) or matchs.name == matchs._origName:
# if s._priority < matchs._priority:
- self.logger.debug("Found higher priority for sample '%s' with priority '%s' from sample '%s' with priority '%s'" \
- % (s._origName, s._priority, matchs._origName, matchs._priority))
+ self.logger.debug("Found higher priority for sample '%s' with priority '%s' from sample " %
+ (s._origName, s._priority) +
+ "'%s' with priority '%s'" % (matchs._origName, matchs._priority))
foundHigherPriority = True
break
else:
othermatches.append(matchs._origName)
if not foundHigherPriority:
- self.logger.debug("Chose sample '%s' from samples '%s' for file '%s'" \
- % (s._origName, othermatches, s.name))
+ self.logger.debug(
+ "Chose sample '%s' from samples '%s' for file '%s'" % (s._origName, othermatches, s.name))
tempsamples.append(s)
# Now we have two lists, tempsamples which contains only the highest priority matches, and
@@ -625,13 +639,14 @@ def parse(self):
# 6/22/12 CS Added support for non-overrideable (locked) settings
# logger.debug("Locked settings: %s" % pprint.pformat(matchs._lockedSettings))
# if settingname in matchs._lockedSettings:
- # logger.debug("Matched setting '%s' in sample '%s' lockedSettings" \
+ # logger.debug("Matched setting '%s' in sample '%s' lockedSettings"
# % (settingname, matchs.name))
- if (destsetting == None or destsetting == getattr(self, settingname)) \
- and sourcesetting != None and sourcesetting != getattr(self, settingname) \
- and not settingname in s._lockedSettings:
- self.logger.debug("Overriding setting '%s' with value '%s' from sample '%s' to sample '%s' in app '%s'" \
- % (settingname, sourcesetting, overridesample._origName, s.name, s.app))
+ if (destsetting is None or destsetting == getattr(self, settingname)) \
+ and sourcesetting is not None and sourcesetting != getattr(self, settingname) \
+ and settingname not in s._lockedSettings:
+ self.logger.debug("Overriding setting '%s' with value '%s' from sample '%s' to " %
+ (settingname, sourcesetting, overridesample._origName) +
+ "sample '%s' in app '%s'" % (s.name, s.app))
setattr(s, settingname, sourcesetting)
except AttributeError:
pass
@@ -649,7 +664,8 @@ def parse(self):
# We've added replay mode, so lets loop through the samples again and set the earliest and latest
# settings for any samples that were set to replay mode
if s.perDayVolume:
- self.logger.info("Stanza contains per day volume, changing rater and generator to perdayvolume instead of count")
+ self.logger.info(
+ "Stanza contains per day volume, changing rater and generator to perdayvolume instead of count")
s.rater = 'perdayvolume'
s.count = 1
s.generator = 'perdayvolumegenerator'
@@ -676,7 +692,7 @@ def parse(self):
if s.autotimestamp:
at = self.autotimestamps
- line_puncts = [ ]
+ line_puncts = []
# Check for _time field, if it exists, add a timestamp to support it
if len(s.sampleDict) > 0:
@@ -712,7 +728,8 @@ def parse(self):
t.replacement = x[1]
try:
- self.logger.debug("Trying regex '%s' for format '%s' on '%s'" % (x[0], x[1], e[s.timeField]))
+ self.logger.debug(
+ "Trying regex '%s' for format '%s' on '%s'" % (x[0], x[1], e[s.timeField]))
ts = s.getTSFromEvent(e['_raw'], t)
if type(ts) == datetime.datetime:
found_token = False
@@ -722,10 +739,11 @@ def parse(self):
found_token = True
break
if not found_token:
- self.logger.debug("Found timestamp '%s', extending token with format '%s'" % (x[0], x[1]))
+ self.logger.debug(
+ "Found timestamp '%s', extending token with format '%s'" % (x[0], x[1]))
s.tokens.append(t)
# Drop this pattern from ones we try in the future
- at = [ z for z in at if z[0] != x[0] ]
+ at = [z for z in at if z[0] != x[0]]
break
except ValueError:
pass
@@ -749,23 +767,23 @@ def _validateSetting(self, stanza, key, value):
self.logger.debug("Validating setting for '%s' with value '%s' in stanza '%s'" % (key, value, stanza))
if key.find('token.') > -1:
results = re.match('token\.(\d+)\.(\w+)', key)
- if results != None:
+ if results is not None:
groups = results.groups()
if groups[1] not in self._validTokenTypes:
- self.logger.error("Could not parse token index '%s' token type '%s' in stanza '%s'" % \
- (groups[0], groups[1], stanza))
- raise ValueError("Could not parse token index '%s' token type '%s' in stanza '%s'" % \
- (groups[0], groups[1], stanza))
+ self.logger.error("Could not parse token index '%s' token type '%s' in stanza '%s'" %
+ (groups[0], groups[1], stanza))
+ raise ValueError("Could not parse token index '%s' token type '%s' in stanza '%s'" %
+ (groups[0], groups[1], stanza))
if groups[1] == 'replacementType':
if value not in self._validReplacementTypes:
- self.logger.error("Invalid replacementType '%s' for token index '%s' in stanza '%s'" % \
- (value, groups[0], stanza))
- raise ValueError("Could not parse token index '%s' token type '%s' in stanza '%s'" % \
- (groups[0], groups[1], stanza))
+ self.logger.error("Invalid replacementType '%s' for token index '%s' in stanza '%s'" %
+ (value, groups[0], stanza))
+ raise ValueError("Could not parse token index '%s' token type '%s' in stanza '%s'" %
+ (groups[0], groups[1], stanza))
return (int(groups[0]), groups[1])
elif key.find('host.') > -1:
results = re.match('host\.(\w+)', key)
- if results != None:
+ if results is not None:
groups = results.groups()
if groups[0] not in self._validHostTokens:
self.logger.error("Could not parse host token type '%s' in stanza '%s'" % (groups[0], stanza))
@@ -811,8 +829,9 @@ def _validateSetting(self, stanza, key, value):
self.logger.debug("Calling function for setting '%s' with value '%s'" % (key, value))
value = complexSetting(value)
elif isinstance(complexSetting, list):
- if not value in complexSetting:
- self.logger.error("Setting '%s' is invalid for value '%s' in stanza '%s'" % (key, value, stanza))
+ if value not in complexSetting:
+ self.logger.error(
+ "Setting '%s' is invalid for value '%s' in stanza '%s'" % (key, value, stanza))
raise ValueError("Setting '%s' is invalid for value '%s' in stanza '%s'" % (key, value, stanza))
else:
# Notifying only if the setting isn't valid and continuing on
@@ -832,7 +851,7 @@ def _validateTimezone(self, value):
mod = 100
else:
mod = -100
- value = datetime.timedelta(hours=int(int(value) / 100.0), minutes=int(value) % mod )
+ value = datetime.timedelta(hours=int(int(value) / 100.0), minutes=int(value) % mod)
except:
self.logger.error("Could not parse timezone {}".format(value))
raise ValueError("Could not parse timezone {}".format(value))
@@ -855,7 +874,6 @@ def _buildConfDict(self):
"""Build configuration dictionary that we will use """
# Abstracts grabbing configuration from Splunk or directly from Configuration Files
-
if self.splunkEmbedded and not STANDALONE:
self.logger.info('Retrieving eventgen configurations from /configs/eventgen')
import splunk.entity as entity
@@ -866,9 +884,7 @@ def _buildConfDict(self):
conf = ConfigParser()
# Make case sensitive
conf.optionxform = str
- currentdir = os.getcwd()
-
- conffiles = [ ]
+ conffiles = []
# 2/1/15 CS Moving to argparse way of grabbing command line parameters
if self.configfile:
if os.path.exists(self.configfile):
@@ -876,26 +892,26 @@ def _buildConfDict(self):
# In which case we'll assume it's a splunk app and look for config files in
# default and local
if os.path.isdir(self.configfile):
- conffiles = [os.path.join(self.grandparentdir, 'default', 'eventgen.conf'),
- os.path.join(self.configfile, 'default', 'eventgen.conf'),
- os.path.join(self.configfile, 'local', 'eventgen.conf')]
+ conffiles = [
+ os.path.join(self.grandparentdir, 'default', 'eventgen.conf'),
+ os.path.join(self.configfile, 'default', 'eventgen.conf'),
+ os.path.join(self.configfile, 'local', 'eventgen.conf')]
else:
- conffiles = [os.path.join(self.grandparentdir, 'default', 'eventgen.conf'),
- self.configfile]
+ conffiles = [os.path.join(self.grandparentdir, 'default', 'eventgen.conf'), self.configfile]
if len(conffiles) == 0:
- conffiles = [os.path.join(self.grandparentdir, 'default', 'eventgen.conf'),
- os.path.join(self.grandparentdir, 'local', 'eventgen.conf')]
+ conffiles = [
+ os.path.join(self.grandparentdir, 'default', 'eventgen.conf'),
+ os.path.join(self.grandparentdir, 'local', 'eventgen.conf')]
self.logger.debug('Reading configuration files for non-splunkembedded: %s' % conffiles)
conf.read(conffiles)
sections = conf.sections()
- ret = { }
- orig = { }
+ ret = {}
for section in sections:
ret[section] = dict(conf.items(section))
# For compatibility with Splunk's configs, need to add the app name to an eai:acl key
- ret[section]['eai:acl'] = { 'app': self.grandparentdir.split(os.sep)[-1] }
+ ret[section]['eai:acl'] = {'app': self.grandparentdir.split(os.sep)[-1]}
self._confDict = ret
self.logger.debug("ConfDict returned %s" % pprint.pformat(dict(self._confDict)))
diff --git a/splunk_eventgen/lib/eventgenexceptions.py b/splunk_eventgen/lib/eventgenexceptions.py
index f954192c..3d0d0d91 100644
--- a/splunk_eventgen/lib/eventgenexceptions.py
+++ b/splunk_eventgen/lib/eventgenexceptions.py
@@ -3,9 +3,7 @@
"""
-
class PluginNotLoaded(Exception):
-
def __init__(self, bindir, libdir, plugindir, name, type, msg="Plugin {} Not Loaded, attempting to load."):
"""Exception raised when a sample asks for a plugin that is not in the plugin list.
This exception triggers an upload reload of plugins that expands the search path of plugins to add.
@@ -26,8 +24,8 @@ def __init__(self, bindir, libdir, plugindir, name, type, msg="Plugin {} Not Loa
self.type = type
super(PluginNotLoaded, self).__init__(msg)
-class FailedLoadingPlugin(Exception):
+class FailedLoadingPlugin(Exception):
def __init__(self, name, msg="Plugin {} Not Found or Failed to load."):
"""Exception raised when a sample asks for a plugin that can't be found
diff --git a/splunk_eventgen/lib/eventgenoutput.py b/splunk_eventgen/lib/eventgenoutput.py
index b8454dc6..c2b8c1c1 100644
--- a/splunk_eventgen/lib/eventgenoutput.py
+++ b/splunk_eventgen/lib/eventgenoutput.py
@@ -1,12 +1,13 @@
from __future__ import division
+
+import datetime
import logging
import logging.handlers
-from Queue import Full
-import json
import time
-import datetime
+from Queue import Full
+
-#TODO: Figure out why we load plugins from here instead of the base plugin class.
+# TODO: Figure out why we load plugins from here instead of the base plugin class.
class Output(object):
"""
Base class which loads output plugins in BASE_DIR/lib/plugins/output and handles queueing
@@ -22,11 +23,10 @@ def __init__(self, sample):
self._setup_logging()
self.output_counter = None
-
def __str__(self):
"""Only used for debugging, outputs a pretty printed representation of this output"""
# Eliminate recursive going back to parent
- temp = dict([ (key, value) for (key, value) in self.__dict__.items() if key != '_c'])
+ # temp = dict([(key, value) for (key, value) in self.__dict__.items() if key != '_c'])
# return pprint.pformat(temp)
return ""
@@ -55,18 +55,18 @@ def setOutputCounter(self, output_counter):
def updateConfig(self, config):
self.config = config
- #TODO: This is where the actual output plugin is loaded, and pushed out. This should be handled way better...
+ # TODO: This is where the actual output plugin is loaded, and pushed out. This should be handled way better...
self.outputPlugin = self.config.getPlugin('output.' + self._sample.outputMode, self._sample)
def send(self, msg):
"""
Adds msg to the output buffer, flushes if buffer is more than MAXQUEUELENGTH
"""
- ts = self._sample.timestamp if self._sample.timestamp != None else self._sample.now()
- self._queue.append({'_raw': msg, 'index': self._sample.index,
- 'source': self._sample.source, 'sourcetype': self._sample.sourcetype,
- 'host': self._sample.host, 'hostRegex': self._sample.hostRegex,
- '_time': int(time.mktime(ts.timetuple()))})
+ ts = self._sample.timestamp if self._sample.timestamp is not None else self._sample.now()
+ self._queue.append({
+ '_raw': msg, 'index': self._sample.index, 'source': self._sample.source, 'sourcetype':
+ self._sample.sourcetype, 'host': self._sample.host, 'hostRegex': self._sample.hostRegex, '_time': int(
+ time.mktime(ts.timetuple()))})
if len(self._queue) >= self.MAXQUEUELENGTH:
self.flush()
@@ -90,7 +90,7 @@ def flush(self, endOfInterval=False):
more than maxIntervalsBeforeFlush tunable.
"""
flushing = False
- #TODO: Fix interval flushing somehow with a queue, not sure I even want to support this feature anymore.
+ # TODO: Fix interval flushing somehow with a queue, not sure I even want to support this feature anymore.
'''if endOfInterval:
logger.debugv("Sample calling flush, checking increment against maxIntervalsBeforeFlush")
c.intervalsSinceFlush[self._sample.name].increment()
@@ -104,7 +104,7 @@ def flush(self, endOfInterval=False):
logger.debugv("maxQueueLength exceeded, flushing")
flushing = True'''
- #TODO: This is set this way just for the time being while I decide if we want this feature.
+ # TODO: This is set this way just for the time being while I decide if we want this feature.
flushing = True
if flushing:
q = self._queue
@@ -113,8 +113,10 @@ def flush(self, endOfInterval=False):
outputer = self.outputPlugin(self._sample, self.output_counter)
outputer.updateConfig(self.config)
outputer.set_events(q)
- # When an outputQueue is used, it needs to run in a single threaded nature which requires to be put back into the outputqueue so a single thread worker can execute it.
- # When an outputQueue is not used, it can be ran by multiple processes or threads. Therefore, no need to put the outputer back into the Queue. Just execute it.
+ # When an outputQueue is used, it needs to run in a single threaded nature which requires to be put back
+ # into the outputqueue so a single thread worker can execute it. When an outputQueue is not used, it can be
+ # ran by multiple processes or threads. Therefore, no need to put the outputer back into the Queue. Just
+ # execute it.
# if outputPlugin must be used for useOutputQueue, use outputQueue regardless of user config useOutputQueue:
if self.outputPlugin.useOutputQueue or self.config.useOutputQueue:
try:
@@ -126,9 +128,10 @@ def flush(self, endOfInterval=False):
# TODO: clean out eventsSend and bytesSent if they are not being used in config
# self.config.eventsSent.add(len(tmp))
# self.config.bytesSent.add(sum(tmp))
- if self.config.splunkEmbedded and len(tmp)>0:
+ if self.config.splunkEmbedded and len(tmp) > 0:
metrics = logging.getLogger('eventgen_metrics')
- metrics.info({'timestamp': datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d %H:%M:%S'),
- 'sample': self._sample.name, 'events': len(tmp), 'bytes': sum(tmp)})
+ metrics.info({
+ 'timestamp': datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d %H:%M:%S'), 'sample':
+ self._sample.name, 'events': len(tmp), 'bytes': sum(tmp)})
tmp = None
outputer.run()
diff --git a/splunk_eventgen/lib/eventgensamples.py b/splunk_eventgen/lib/eventgensamples.py
index 7e14fb3f..8a0c21b3 100644
--- a/splunk_eventgen/lib/eventgensamples.py
+++ b/splunk_eventgen/lib/eventgensamples.py
@@ -1,14 +1,17 @@
# TODO Move config settings to plugins
from __future__ import division, with_statement
-import os, sys
+
+import copy
+import csv
+import datetime
import logging
+import os
import pprint
-import datetime
import re
-import csv
-import copy
+import sys
import urllib
+
from timeparser import timeParser
@@ -23,7 +26,7 @@ class Sample(object):
name = None
app = None
filePath = None
-
+
# Options which are all valid for a sample
disabled = None
spoolDir = None
@@ -83,6 +86,8 @@ class Sample(object):
end = None
queueable = None
autotimestamp = None
+ extendIndexes = None
+ index_list = []
# Internal fields
sampleLines = None
@@ -93,11 +98,11 @@ class Sample(object):
_lastts = None
_earliestParsed = None
_latestParsed = None
-
+
def __init__(self, name):
self.name = name
- self.tokens = [ ]
- self._lockedSettings = [ ]
+ self.tokens = []
+ self._lockedSettings = []
self.backfilldone = False
self._setup_logging()
@@ -106,10 +111,10 @@ def updateConfig(self, config):
def __str__(self):
"""Only used for debugging, outputs a pretty printed representation of this sample"""
- filter_list = [ 'sampleLines', 'sampleDict' ]
- temp = dict([ (key, value) for (key, value) in self.__dict__.items() if key not in filter_list ])
+ filter_list = ['sampleLines', 'sampleDict']
+ temp = dict([(key, value) for (key, value) in self.__dict__.items() if key not in filter_list])
return pprint.pformat(temp)
-
+
def __repr__(self):
return self.__str__()
@@ -128,17 +133,17 @@ def _setup_logging(self):
logger = logging.getLogger('eventgen')
self.logger = logger
- ## Replaces $SPLUNK_HOME w/ correct pathing
+ # Replaces $SPLUNK_HOME w/ correct pathing
def pathParser(self, path):
greatgreatgrandparentdir = os.path.dirname(os.path.dirname(self.config.grandparentdir))
sharedStorage = ['$SPLUNK_HOME/etc/apps', '$SPLUNK_HOME/etc/users/', '$SPLUNK_HOME/var/run/splunk']
- ## Replace windows os.sep w/ nix os.sep
+ # Replace windows os.sep w/ nix os.sep
path = path.replace('\\', '/')
- ## Normalize path to os.sep
+ # Normalize path to os.sep
path = os.path.normpath(path)
- ## Iterate special paths
+ # Iterate special paths
for x in range(0, len(sharedStorage)):
sharedPath = os.path.normpath(sharedStorage[x])
@@ -146,17 +151,17 @@ def pathParser(self, path):
path.replace('$SPLUNK_HOME', greatgreatgrandparentdir)
break
- ## Split path
+ # Split path
path = path.split(os.sep)
- ## Iterate path segments
+ # Iterate path segments
for x in range(0, len(path)):
segment = path[x].lstrip('$')
- ## If segement is an environment variable then replace
- if os.environ.has_key(segment):
+ # If segement is an environment variable then replace
+ if segment in os.environ:
path[x] = os.environ[segment]
- ## Join path
+ # Join path
path = os.sep.join(path)
return path
@@ -164,11 +169,11 @@ def pathParser(self, path):
# 9/2/15 Adding ability to pass in a token rather than using the tokens from the sample
def getTSFromEvent(self, event, passed_token=None):
currentTime = None
- formats = [ ]
+ formats = []
# JB: 2012/11/20 - Can we optimize this by only testing tokens of type = *timestamp?
# JB: 2012/11/20 - Alternatively, documentation should suggest putting timestamp as token.0.
- if passed_token != None:
- tokens = [ passed_token ]
+ if passed_token is not None:
+ tokens = [passed_token]
else:
tokens = self.tokens
for token in tokens:
@@ -182,14 +187,16 @@ def getTSFromEvent(self, event, passed_token=None):
timeString = results.group(group)
# self.logger.debug("Testing '%s' as a time string against '%s'" % (timeString, timeFormat))
if timeFormat == "%s":
- ts = float(timeString) if len(timeString) < 10 else float(timeString) / (10**(len(timeString)-10))
+ ts = float(timeString) if len(timeString) < 10 else float(timeString) \
+ / (10**(len(timeString) - 10))
# self.logger.debug("Getting time for timestamp '%s'" % ts)
currentTime = datetime.datetime.fromtimestamp(ts)
else:
- # self.logger.debugv("Getting time for timeFormat '%s' and timeString '%s'" % (timeFormat, timeString))
- # Working around Python bug with a non thread-safe strptime. Randomly get AttributeError
+ # self.logger.debug("Getting time for timeFormat '%s' and timeString '%s'" %
+ # (timeFormat, timeString))
+ # Working around Python bug with a non thread-safe strptime. Randomly get AttributeError
# when calling strptime, so if we get that, try again
- while currentTime == None:
+ while currentTime is None:
try:
# Checking for timezone adjustment
if timeString[-5] == "+":
@@ -201,11 +208,13 @@ def getTSFromEvent(self, event, passed_token=None):
if type(currentTime) == datetime.datetime:
break
except ValueError:
- self.logger.warning("Match found ('%s') but time parse failed. Timeformat '%s' Event '%s'" % (timeString, timeFormat, event))
+ self.logger.warning("Match found ('%s') but time parse failed. Timeformat '%s' Event '%s'" %
+ (timeString, timeFormat, event))
if type(currentTime) != datetime.datetime:
# Total fail
- if passed_token == None: # If we're running for autotimestamp don't log error
- self.logger.warning("Can't find a timestamp (using patterns '%s') in this event: '%s'." % (formats, event))
+ if passed_token is None: # If we're running for autotimestamp don't log error
+ self.logger.warning(
+ "Can't find a timestamp (using patterns '%s') in this event: '%s'." % (formats, event))
raise ValueError("Can't find a timestamp (using patterns '%s') in this event: '%s'." % (formats, event))
# Check to make sure we parsed a year
if currentTime.year == 1900:
@@ -216,18 +225,18 @@ def getTSFromEvent(self, event, passed_token=None):
# if self.timestamp == None:
# self.timestamp = currentTime
return currentTime
-
+
def saveState(self):
"""Saves state of all integer IDs of this sample to a file so when we restart we'll pick them up"""
for token in self.tokens:
if token.replacementType == 'integerid':
- stateFile = open(os.path.join(self.sampleDir, 'state.'+urllib.pathname2url(token.token)), 'w')
+ stateFile = open(os.path.join(self.sampleDir, 'state.' + urllib.pathname2url(token.token)), 'w')
stateFile.write(token.replacement)
stateFile.close()
def now(self, utcnow=False, realnow=False):
# self.logger.info("Getting time (timezone %s)" % (self.timezone))
- if not self.backfilldone and not self.backfillts == None and not realnow:
+ if not self.backfilldone and self.backfillts is not None and not realnow:
return self.backfillts
elif self.timezone.days > 0:
return datetime.datetime.now()
@@ -246,11 +255,12 @@ def get_backfill_time(self, current_time):
if self.backfill[-2:] == 'ms':
time_unit = 'ms'
backfill_time = self.backfill[1:-2]
- return self.get_time_difference(current_time=current_time, different_time=backfill_time, sign='-', time_unit=time_unit)
+ return self.get_time_difference(current_time=current_time, different_time=backfill_time, sign='-',
+ time_unit=time_unit)
else:
self.logger.error("Backfill time is not in the past.")
return current_time
-
+
def get_time_difference(self, current_time, different_time, sign='-', time_unit='ms'):
if time_unit == 'ms':
return current_time + (int(sign + '1') * datetime.timedelta(milliseconds=int(different_time)))
@@ -263,13 +273,10 @@ def get_time_difference(self, current_time, different_time, sign='-', time_unit=
elif time_unit == 'd':
return current_time + (int(sign + '1') * datetime.timedelta(days=int(different_time)))
-
-
-
def earliestTime(self):
# First optimization, we need only store earliest and latest
# as an offset of now if they're relative times
- if self._earliestParsed != None:
+ if self._earliestParsed is not None:
earliestTime = self.now() - self._earliestParsed
self.logger.debug("Using cached earliest time: %s" % earliestTime)
else:
@@ -280,14 +287,16 @@ def earliestTime(self):
temptd = self.now(realnow=True) - tempearliest
self._earliestParsed = datetime.timedelta(days=temptd.days, seconds=temptd.seconds)
earliestTime = self.now() - self._earliestParsed
- self.logger.debug("Calulating earliestParsed as '%s' with earliestTime as '%s' and self.sample.earliest as '%s'" % (self._earliestParsed, earliestTime, tempearliest))
+ self.logger.debug(
+ "Calulating earliestParsed as '%s' with earliestTime as '%s' and self.sample.earliest as '%s'" %
+ (self._earliestParsed, earliestTime, tempearliest))
else:
earliestTime = timeParser(self.earliest, timezone=self.timezone)
self.logger.debug("earliestTime as absolute time '%s'" % earliestTime)
return earliestTime
def latestTime(self):
- if self._latestParsed != None:
+ if self._latestParsed is not None:
latestTime = self.now() - self._latestParsed
self.logger.debug("Using cached latestTime: %s" % latestTime)
else:
@@ -298,7 +307,9 @@ def latestTime(self):
temptd = self.now(realnow=True) - templatest
self._latestParsed = datetime.timedelta(days=temptd.days, seconds=temptd.seconds)
latestTime = self.now() - self._latestParsed
- self.logger.debug("Calulating latestParsed as '%s' with latestTime as '%s' and self.sample.latest as '%s'" % (self._latestParsed, latestTime, templatest))
+ self.logger.debug(
+ "Calulating latestParsed as '%s' with latestTime as '%s' and self.sample.latest as '%s'" %
+ (self._latestParsed, latestTime, templatest))
else:
latestTime = timeParser(self.latest, timezone=self.timezone)
self.logger.debug("latstTime as absolute time '%s'" % latestTime)
@@ -316,33 +327,36 @@ def _closeSampleFile(self):
self._sampleFH.close()
def loadSample(self):
+ """
+ Load sample from disk into self._sample.sampleLines and self._sample.sampleDict, using cached copy if possible
+ """
if not self.logger:
self._setup_logging()
- """Load sample from disk into self._sample.sampleLines and self._sample.sampleDict,
- using cached copy if possible"""
if self.sampletype == 'raw':
# 5/27/12 CS Added caching of the sample file
- if self.sampleDict == None:
+ if self.sampleDict is None:
self._openSampleFile()
if self.breaker == self.config.breaker:
self.logger.debug("Reading raw sample '%s' in app '%s'" % (self.name, self.app))
self.sampleLines = self._sampleFH.readlines()
- # 1/5/14 CS Moving to using only sampleDict and doing the breaking up into events at load time instead of on every generation
+ # 1/5/14 CS Moving to using only sampleDict and doing the breaking up into events at load time instead
+ # of on every generation
else:
- self.logger.debug("Non-default breaker '%s' detected for sample '%s' in app '%s'" \
- % (self.breaker, self.name, self.app) )
+ self.logger.debug("Non-default breaker '%s' detected for sample '%s' in app '%s'" %
+ (self.breaker, self.name, self.app))
sampleData = self._sampleFH.read()
- self.sampleLines = [ ]
+ self.sampleLines = []
- self.logger.debug("Filling array for sample '%s' in app '%s'; sampleData=%s, breaker=%s" \
- % (self.name, self.app, len(sampleData), self.breaker))
+ self.logger.debug("Filling array for sample '%s' in app '%s'; sampleData=%s, breaker=%s" %
+ (self.name, self.app, len(sampleData), self.breaker))
try:
breakerRE = re.compile(self.breaker, re.M)
except:
- self.logger.error("Line breaker '%s' for sample '%s' in app '%s' could not be compiled; using default breaker" \
- % (self.breaker, self.name, self.app) )
+ self.logger.error(
+ "Line breaker '%s' for sample '%s' in app '%s' could not be compiled; using default breaker"
+ % (self.breaker, self.name, self.app))
self.breaker = self.config.breaker
# Loop through data, finding matches of the regular expression and breaking them up into
@@ -365,14 +379,17 @@ def loadSample(self):
for line in self.sampleLines:
if line and line[-1] != '\n':
line = line + '\n'
- self.sampleDict.append({ '_raw': line, 'index': self.index, 'host': self.host, 'source': self.source, 'sourcetype': self.sourcetype })
- self.logger.debug('Finished creating sampleDict & sampleLines. Len samplesLines: %d Len sampleDict: %d' % (len(self.sampleLines), len(self.sampleDict)))
+ self.sampleDict.append({
+ '_raw': line, 'index': self.index, 'host': self.host, 'source': self.source, 'sourcetype':
+ self.sourcetype})
+ self.logger.debug('Finished creating sampleDict & sampleLines. Len samplesLines: %d Len sampleDict: %d'
+ % (len(self.sampleLines), len(self.sampleDict)))
elif self.sampletype == 'csv':
- if self.sampleDict == None:
+ if self.sampleDict is None:
self._openSampleFile()
self.logger.debug("Reading csv sample '%s' in app '%s'" % (self.name, self.app))
- self.sampleDict = [ ]
- self.sampleLines = [ ]
+ self.sampleDict = []
+ self.sampleLines = []
# Fix to load large csv files, work with python 2.5 onwards
csv.field_size_limit(sys.maxint)
csvReader = csv.DictReader(self._sampleFH)
@@ -395,14 +412,29 @@ def loadSample(self):
else:
self.logger.error("Missing _raw in line '%s'" % pprint.pformat(line))
self._closeSampleFile()
- self.logger.debug("Finished creating sampleDict & sampleLines for sample '%s'. Len sampleDict: %d" % (self.name, len(self.sampleDict)))
+ self.logger.debug("Finished creating sampleDict & sampleLines for sample '%s'. Len sampleDict: %d" %
+ (self.name, len(self.sampleDict)))
for i in xrange(0, len(self.sampleDict)):
if len(self.sampleDict[i]['_raw']) < 1 or self.sampleDict[i]['_raw'][-1] != '\n':
self.sampleDict[i]['_raw'] += '\n'
+ if self.extendIndexes:
+ try:
+ for index_item in self.extendIndexes.split(','):
+ index_item = index_item.strip()
+ if ':' in index_item:
+ extend_indexes_count = int(index_item.split(':')[-1])
+ extend_indexes_prefix = index_item.split(':')[0] + "{}"
+ self.index_list.extend([extend_indexes_prefix.format(_i) for _i in range(extend_indexes_count)])
+ elif len(index_item):
+ self.index_list.append(index_item)
+ except Exception:
+ self.logger.error("Failed to parse extendIndexes, using index={} now.".format(self.index))
+ self.index_list = []
+ self.extendIndexes = None
def get_loaded_sample(self):
- if self.sampletype != 'csv' and os.path.getsize(self.filePath) > 10000000 :
+ if self.sampletype != 'csv' and os.path.getsize(self.filePath) > 10000000:
self._openSampleFile()
return self._sampleFH
elif self.sampletype == 'csv':
diff --git a/splunk_eventgen/lib/eventgentimer.py b/splunk_eventgen/lib/eventgentimer.py
index 6079cbaa..364b9686 100644
--- a/splunk_eventgen/lib/eventgentimer.py
+++ b/splunk_eventgen/lib/eventgentimer.py
@@ -1,24 +1,26 @@
+import copy
import logging
import time
-import copy
-from timeparser import timeParserTimeMath
from Queue import Full
+from timeparser import timeParserTimeMath
+
+
class Timer(object):
"""
- Overall governor in Eventgen. A timer is created for every sample in Eventgen. The Timer has the responsibility
- for executing each sample. There are two ways the timer can execute:
+ Overall governor in Eventgen. A timer is created for every sample in Eventgen. The Timer has the responsibility
+ for executing each sample. There are two ways the timer can execute:
* Queueable
* Non-Queueable
- For Queueable plugins, we place a work item in the generator queue. Generator workers pick up the item from the generator
- queue and do work. This queueing architecture allows for parallel execution of workers. Workers then place items in the
- output queue for Output workers to pick up and output.
+ For Queueable plugins, we place a work item in the generator queue. Generator workers pick up the item from the
+ generator queue and do work. This queueing architecture allows for parallel execution of workers. Workers then place
+ items in the output queue for Output workers to pick up and output.
- However, for some generators, like the replay generator, we need to keep a single view of state of where we are in the replay.
- This means we cannot generate items in parallel. This is why we also offer Non-Queueable plugins. In the case of
- Non-Queueable plugins, the Timer class calls the generator method of the plugin directly, tracks the amount of time
- the plugin takes to generate and sleeps the remaining interval before calling generate again.
+ However, for some generators, like the replay generator, we need to keep a single view of state of where we are in
+ the replay. This means we cannot generate items in parallel. This is why we also offer Non-Queueable plugins. In
+ the case of Non-Queueable plugins, the Timer class calls the generator method of the plugin directly, tracks the
+ amount of time the plugin takes to generate and sleeps the remaining interval before calling generate again.
"""
time = None
countdown = None
@@ -39,23 +41,23 @@ def __init__(self, time, sample=None, config=None, genqueue=None, outputqueue=No
self.countdown = 0
self.executions = 0
self.interval = getattr(self.sample, "interval", config.interval)
- #enable the logger
self._setup_logging()
self.logger.debug('Initializing timer for %s' % sample.name if sample is not None else "None")
# load plugins
- if self.sample != None:
+ if self.sample is not None:
rater_class = self.config.getPlugin('rater.' + self.sample.rater, self.sample)
self.rater = rater_class(self.sample)
self.generatorPlugin = self.config.getPlugin('generator.' + self.sample.generator, self.sample)
self.outputPlugin = self.config.getPlugin('output.' + self.sample.outputMode, self.sample)
if self.sample.timeMultiple < 0:
self.logger.error("Invalid setting for timeMultiple: {}, value should be positive".format(
- self.sample.timeMultiple))
+ self.sample.timeMultiple))
elif self.sample.timeMultiple != 1:
self.interval = self.sample.interval * self.sample.timeMultiple
self.logger.debug("Adjusting interval {} with timeMultiple {}, new interval: {}".format(
- self.sample.interval, self.sample.timeMultiple, self.interval))
- self.logger.info("Start '%s' generatorWorkers for sample '%s'" % (self.sample.config.generatorWorkers, self.sample.name))
+ self.sample.interval, self.sample.timeMultiple, self.interval))
+ self.logger.info(
+ "Start '%s' generatorWorkers for sample '%s'" % (self.sample.config.generatorWorkers, self.sample.name))
# loggers can't be pickled due to the lock object, remove them before we try to pickle anything.
def __getstate__(self):
@@ -105,18 +107,20 @@ def real_run(self):
end = False
previous_count_left = 0
raw_event_size = self.predict_event_size()
- if self.end and int(self.end) == 0:
- self.logger.info("End = 0, no events will be generated for sample '%s'" % self.sample.name)
- end = True
+ if self.end:
+ if int(self.end) == 0:
+ self.logger.info("End = 0, no events will be generated for sample '%s'" % self.sample.name)
+ end = True
+ elif int(self.end) == -1:
+ self.logger.info("End is set to -1. Will be running without stopping for sample %s" % self.sample.name)
while not end:
# Need to be able to stop threads by the main thread or this thread. self.config will stop all threads
# referenced in the config object, while, self.stopping will only stop this one.
if self.config.stopping or self.stopping:
end = True
count = self.rater.rate()
- #First run of the generator, see if we have any backfill work to do.
+ # First run of the generator, see if we have any backfill work to do.
if self.countdown <= 0:
-
if self.sample.backfill and not self.sample.backfilldone:
realtime = self.sample.now(realnow=True)
if "-" in self.sample.backfill[0]:
@@ -130,34 +134,35 @@ def real_run(self):
backfillnumber += char
elif char != "-":
backfillletter += char
- backfillearliest = timeParserTimeMath(plusminus=mathsymbol,
- num=backfillnumber,
- unit=backfillletter,
+ backfillearliest = timeParserTimeMath(plusminus=mathsymbol, num=backfillnumber, unit=backfillletter,
ret=realtime)
while backfillearliest < realtime:
+ if self.executions == int(self.end):
+ self.logger.info("End executions %d reached, ending generation of sample '%s'" % (int(
+ self.end), self.sample.name))
+ break
et = backfillearliest
lt = timeParserTimeMath(plusminus="+", num=self.interval, unit="s", ret=et)
genPlugin = self.generatorPlugin(sample=self.sample)
# need to make sure we set the queue right if we're using multiprocessing or thread modes
genPlugin.updateConfig(config=self.config, outqueue=self.outputQueue)
- genPlugin.updateCounts(count=count,
- start_time=et,
- end_time=lt)
+ genPlugin.updateCounts(count=count, start_time=et, end_time=lt)
try:
self.generatorQueue.put(genPlugin)
+ self.executions += 1
except Full:
self.logger.warning("Generator Queue Full. Skipping current generation.")
backfillearliest = lt
+
self.sample.backfilldone = True
else:
# 12/15/13 CS Moving the rating to a separate plugin architecture
# Save previous interval count left to avoid perdayvolumegenerator drop small tasks
if self.sample.generator == 'perdayvolumegenerator':
count = self.rater.rate() + previous_count_left
- if count < raw_event_size and count > 0:
- self.logger.info(
- "current interval size is {}, which is smaller than a raw event size {}. wait for the next turn.".format(
- count, raw_event_size))
+ if 0 < count < raw_event_size:
+ self.logger.info("current interval size is {}, which is smaller than a raw event size {}.".
+ format(count, raw_event_size) + "Wait for the next turn.")
previous_count_left = count
self.countdown = self.interval
self.executions += 1
@@ -172,27 +177,33 @@ def real_run(self):
try:
if count < 1 and count != -1:
- self.logger.info("There is no data to be generated in worker {0} because the count is {1}.".format(self.sample.config.generatorWorkers, count))
+ self.logger.info(
+ "There is no data to be generated in worker {0} because the count is {1}.".format(
+ self.sample.config.generatorWorkers, count))
else:
# Spawn workers at the beginning of job rather than wait for next interval
- self.logger.info("Start '%d' generatorWorkers for sample '%s'" % (
- self.sample.config.generatorWorkers, self.sample.name))
+ self.logger.info("Start '%d' generatorWorkers for sample '%s'" %
+ (self.sample.config.generatorWorkers, self.sample.name))
for worker_id in range(self.config.generatorWorkers):
# self.generatorPlugin is only an instance, now we need a real plugin. Make a copy of
# of the sample in case another generator corrupts it.
copy_sample = copy.copy(self.sample)
- tokens = copy.deepcopy(self.sample.tokens)
- copy_sample.tokens = tokens
+ copy_tokens = []
+ for token in self.sample.tokens:
+ copy_tokens.append(token.deepcopy(self.sample))
+ copy_sample.tokens = copy_tokens
genPlugin = self.generatorPlugin(sample=copy_sample)
# Adjust queue for threading mode
genPlugin.updateConfig(config=self.config, outqueue=self.outputQueue)
- genPlugin.updateCounts(count=count,
- start_time=et,
- end_time=lt)
+ genPlugin.updateCounts(count=count, start_time=et, end_time=lt)
try:
self.generatorQueue.put(genPlugin)
- self.logger.info("Worker# {0}: Put {1} MB of events in queue for sample '{2}' with et '{3}' and lt '{4}'".format(worker_id, round((count / 1024.0 / 1024), 4), self.sample.name, et, lt))
+ self.executions += 1
+ self.logger.info(("Worker# {0}: Put {1} MB of events in queue for sample '{2}'" +
+ "with et '{3}' and lt '{4}'").format(
+ worker_id, round((count / 1024.0 / 1024), 4),
+ self.sample.name, et, lt))
except Full:
self.logger.warning("Generator Queue Full. Skipping current generation.")
except Exception as e:
@@ -203,24 +214,29 @@ def real_run(self):
# Sleep until we're supposed to wake up and generate more events
self.countdown = self.interval
- self.executions += 1
# 8/20/15 CS Adding support for ending generation at a certain time
+
if self.end:
+ if int(self.end) == -1:
+ time.sleep(self.time)
+ self.countdown -= self.time
+ continue
# 3/16/16 CS Adding support for ending on a number of executions instead of time
# Should be fine with storing state in this sample object since each sample has it's own unique
# timer thread
if not self.endts:
if self.executions >= int(self.end):
- self.logger.info("End executions %d reached, ending generation of sample '%s'" % (int(self.end), self.sample.name))
+ self.logger.info("End executions %d reached, ending generation of sample '%s'" % (int(
+ self.end), self.sample.name))
self.stopping = True
end = True
elif lt >= self.endts:
- self.logger.info("End Time '%s' reached, ending generation of sample '%s'" % (self.sample.endts, self.sample.name))
+ self.logger.info("End Time '%s' reached, ending generation of sample '%s'" % (self.sample.endts,
+ self.sample.name))
self.stopping = True
end = True
else:
time.sleep(self.time)
self.countdown -= self.time
-
diff --git a/splunk_eventgen/lib/eventgentimestamp.py b/splunk_eventgen/lib/eventgentimestamp.py
index f42fb4d9..d1dca9e5 100644
--- a/splunk_eventgen/lib/eventgentimestamp.py
+++ b/splunk_eventgen/lib/eventgentimestamp.py
@@ -1,9 +1,9 @@
import datetime
-import time
import random
+import time
-class EventgenTimestamp(object):
+class EventgenTimestamp(object):
@staticmethod
def get_random_timestamp(earliest, latest):
if type(earliest) != datetime.datetime or type(latest) != datetime.datetime:
@@ -23,7 +23,8 @@ def get_random_timestamp_backfill(earliest, latest, sample_earliest, sample_late
earliest and latest timestamp gets generated with an interval
sample_earliest and sample_latest are the user config key values from eventgen.conf
we are using earliest as a pivot time and creating a random variance using sample_earliest and sample_latest.
- in this way, we respect an interval passed in by a user and use user input earliest and latest to create a random variance
+ in this way, we respect an interval passed in by a user and use user input earliest and latest to create a
+ random variance.
'''
if type(earliest) != datetime.datetime or type(latest) != datetime.datetime:
raise Exception("Earliest {0} or latest {1} arguments are not datetime objects".format(earliest, latest))
@@ -50,7 +51,8 @@ def get_sequential_timestamp(earliest, latest, slot, total_slot):
latest_in_epoch = time.mktime(latest.timetuple())
if earliest_in_epoch > latest_in_epoch:
raise Exception("Latest time is earlier than earliest time.")
- return datetime.datetime.fromtimestamp(earliest_in_epoch + (latest_in_epoch-earliest_in_epoch)*slot/total_slot)
+ return datetime.datetime.fromtimestamp(earliest_in_epoch +
+ (latest_in_epoch - earliest_in_epoch) * slot / total_slot)
@staticmethod
def _convert_time_difference_to_seconds(time_difference):
diff --git a/splunk_eventgen/lib/eventgentoken.py b/splunk_eventgen/lib/eventgentoken.py
index 9e883e05..d6c402fe 100644
--- a/splunk_eventgen/lib/eventgentoken.py
+++ b/splunk_eventgen/lib/eventgentoken.py
@@ -1,26 +1,29 @@
-# TODO Handle timestamp generation for modular input output where we set sample.timestamp properly when we do a timestamp replacement
+# TODO: Handle timestamp generation for modinput and set sample.timestamp properly for timestamp replacement
from __future__ import division, with_statement
-import os
+
+import datetime
+import json
import logging
+import os
import pprint
import random
-import datetime, time
import re
-import json
-import copy
-from timeparser import timeParser, timeDelta2secs
+import time
import urllib
import uuid
+from timeparser import timeDelta2secs
+
+
class Token(object):
"""Contains data and methods for replacing a token in a given sample"""
token = None
replacementType = None
replacement = None
sample = None
- mvhash = { }
-
+ mvhash = {}
+
_replaytd = None
_lastts = None
_tokenfile = None
@@ -35,24 +38,21 @@ class Token(object):
_stringMatch = None
_listMatch = None
_tokenfilecounter = 0
-
+
def __init__(self, sample=None):
-
+
# Logger already setup by config, just get an instance
self._setup_logging()
-
- if sample == None:
- name = "None"
- else:
- name = sample.name
-
self._earliestTime = (None, None)
self._latestTime = (None, None)
-
+
+ if sample:
+ self.sample = sample
+
def __str__(self):
"""Only used for debugging, outputs a pretty printed representation of this token"""
# Eliminate recursive going back to parent
- temp = dict([ (key, value) for (key, value) in self.__dict__.items() if key != 'sample' ])
+ temp = dict([(key, value) for (key, value) in self.__dict__.items() if key != 'sample'])
return pprint.pformat(temp)
def __repr__(self):
@@ -68,18 +68,26 @@ def __getstate__(self):
def __setstate__(self, d):
self.__dict__ = d
self._setup_logging()
+
+ def deepcopy(self, sample=None):
+ # temp = dict([(key, value) for (key, value) in token_object.items() if key != 'sample' and key != 'logger'])
+ cp = Token()
+ cp.__setstate__(self.__getstate__())
+ if sample:
+ cp.sample = sample
+ return cp
def _setup_logging(self):
self.logger = logging.getLogger('eventgen')
-
+
def _match(self, event):
"""Executes regular expression match and returns the re.Match object"""
return re.match(self.token, event)
-
+
def _search(self, event):
"""Executes regular expression search and returns the re.Match object"""
return re.search(self.token, event)
-
+
def _finditer(self, event):
"""Executes regular expression finditer and returns the re.Match object"""
return re.finditer(self.token, event)
@@ -87,7 +95,7 @@ def _finditer(self, event):
def _findall(self, event):
"""Executes regular expression finditer and returns the re.Match object"""
return re.findall(self.token, event)
-
+
def replace(self, event, et=None, lt=None, s=None, pivot_timestamp=None):
"""Replaces all instances of this token in provided event and returns event"""
if not getattr(self, 'logger', None):
@@ -96,10 +104,11 @@ def replace(self, event, et=None, lt=None, s=None, pivot_timestamp=None):
tokenMatch = list(self._finditer(event))
if len(tokenMatch) > 0:
- replacement = self._getReplacement(event[tokenMatch[0].start(0):tokenMatch[0].end(0)], et, lt, s, pivot_timestamp=pivot_timestamp)
+ replacement = self._getReplacement(event[tokenMatch[0].start(0):tokenMatch[0].end(0)], et, lt, s,
+ pivot_timestamp=pivot_timestamp)
if replacement is not None or self.replacementType == 'replaytimestamp':
# logger.debug("Replacement: '%s'" % replacement)
- ## Iterate matches
+ # Iterate matches
for match in tokenMatch:
# logger.debug("Match: %s" % (match))
try:
@@ -131,8 +140,8 @@ def replace(self, event, et=None, lt=None, s=None, pivot_timestamp=None):
self._replaytd = None
self._lastts = None
return event
-
- def _getReplacement(self, old=None, earliestTime=None, latestTime=None, s=None, pivot_timestamp=None):
+
+ def _getReplacement(self, old=None, earliestTime=None, latestTime=None, s=None, pivot_timestamp=None):
if self.replacementType == 'static':
return self.replacement
# This logic is done in replay.py
@@ -141,86 +150,89 @@ def _getReplacement(self, old=None, earliestTime=None, latestTime=None, s=None,
elif self.replacementType == 'timestamp':
if s.earliest and s.latest:
if earliestTime and latestTime:
- if latestTime>=earliestTime:
+ if latestTime >= earliestTime:
if pivot_timestamp:
replacementTime = pivot_timestamp
- elif s.timestamp == None:
+ elif s.timestamp is None:
minDelta = 0
- ## Compute timeDelta as total_seconds
+ # Compute timeDelta as total_seconds
td = latestTime - earliestTime
if not type(td) == float:
maxDelta = timeDelta2secs(td)
else:
maxDelta = td
- ## Get random timeDelta
- randomDelta = datetime.timedelta(seconds=random.randint(minDelta, maxDelta), microseconds=random.randint(0, latestTime.microsecond if latestTime.microsecond > 0 else 999999))
+ # Get random timeDelta
+ randomDelta = datetime.timedelta(
+ seconds=random.randint(minDelta, maxDelta), microseconds=random.randint(
+ 0, latestTime.microsecond if latestTime.microsecond > 0 else 999999))
- ## Compute replacmentTime
+ # Compute replacmentTime
replacementTime = latestTime - randomDelta
s.timestamp = replacementTime
else:
replacementTime = s.timestamp
- # logger.debug("Generating timestamp for sample '%s' with randomDelta %s, minDelta %s, maxDelta %s, earliestTime %s, latestTime %s, earliest: %s, latest: %s" % (s.name, randomDelta, minDelta, maxDelta, earliestTime, latestTime, s.earliest, s.latest))
-
- replacement = self.replacement.replace('%s', str(round(time.mktime(replacementTime.timetuple()))).rstrip('0').rstrip('.'))
+ replacement = self.replacement.replace(
+ '%s',
+ str(round(time.mktime(replacementTime.timetuple()))).rstrip('0').rstrip('.'))
replacementTime = replacementTime.strftime(replacement)
- ## replacementTime == replacement for invalid strptime specifiers
+ # replacementTime == replacement for invalid strptime specifiers
if replacementTime != self.replacement.replace('%', ''):
return replacementTime
else:
- self.logger.error("Invalid strptime specifier '%s' detected; will not replace" \
- % (self.replacement) )
+ self.logger.error(
+ "Invalid strptime specifier '%s' detected; will not replace" % (self.replacement))
return old
- ## earliestTime/latestTime not proper
+ # earliestTime/latestTime not proper
else:
- self.logger.error("Earliest specifier '%s', value '%s' is greater than latest specifier '%s', value '%s' for sample '%s'; will not replace" \
- % (s.earliest, earliestTime, s.latest, latestTime, s.name) )
+ self.logger.error(("Earliest specifier '%s', value '%s' is greater than latest specifier '%s'" +
+ "value '%s' for sample '%s'; will not replace") %
+ (s.earliest, earliestTime, s.latest, latestTime, s.name))
return old
- ## earliest/latest not proper
+ # earliest/latest not proper
else:
self.logger.error('Earliest or latest specifier were not set; will not replace')
return old
elif self.replacementType in ('random', 'rated'):
- ## Validations:
- if self._integerMatch != None:
+ # Validations:
+ if self._integerMatch is not None:
integerMatch = self._integerMatch
else:
integerRE = re.compile('integer\[([-]?\d+):([-]?\d+)\]', re.I)
integerMatch = integerRE.match(self.replacement)
self._integerMatch = integerMatch
-
- if self._floatMatch != None:
+
+ if self._floatMatch is not None:
floatMatch = self._floatMatch
else:
floatRE = re.compile('float\[(-?\d+|\d+\.(\d+)):(-?\d+|\d+\.(\d+))\]', re.I)
floatMatch = floatRE.match(self.replacement)
self._floatMatch = floatMatch
- if self._stringMatch != None:
+ if self._stringMatch is not None:
stringMatch = self._stringMatch
else:
stringRE = re.compile('string\((\d+)\)', re.I)
stringMatch = stringRE.match(self.replacement)
self._stringMatch = stringMatch
- if self._hexMatch != None:
+ if self._hexMatch is not None:
hexMatch = self._hexMatch
- else:
+ else:
hexRE = re.compile('hex\((\d+)\)', re.I)
hexMatch = hexRE.match(self.replacement)
self._hexMatch = hexMatch
- if self._listMatch != None:
+ if self._listMatch is not None:
listMatch = self._listMatch
else:
listRE = re.compile('list(\[[^\]]+\])', re.I)
listMatch = listRE.match(self.replacement)
self._listMatch = listMatch
- ## Valid replacements: ipv4 | ipv6 | integer[:] | string()
+ # Valid replacements: ipv4 | ipv6 | integer[:] | string()
if self.replacement.lower() == 'ipv4':
x = 0
replacement = ''
@@ -245,7 +257,7 @@ def _getReplacement(self, old=None, earliestTime=None, latestTime=None, s=None,
x = 0
replacement = ''
- ## Give me 6 blocks of 2 hex
+ # Give me 6 blocks of 2 hex
while x < 6:
y = 0
while y < 2:
@@ -271,7 +283,7 @@ def _getReplacement(self, old=None, earliestTime=None, latestTime=None, s=None,
rateFactor *= s.hourOfDayRate[str(s.now())]
except KeyError:
import traceback
- stack = traceback.format_exc()
+ stack = traceback.format_exc()
self.logger.error("Hour of day rate failed for token %s. Stacktrace %s" % stack)
if type(s.dayOfWeekRate) == dict:
try:
@@ -283,13 +295,14 @@ def _getReplacement(self, old=None, earliestTime=None, latestTime=None, s=None,
rateFactor *= s.dayOfWeekRate[str(weekday)]
except KeyError:
import traceback
- stack = traceback.format_exc()
+ stack = traceback.format_exc()
self.logger.error("Day of week rate failed. Stacktrace %s" % stack)
replacementInt = int(round(replacementInt * rateFactor, 0))
replacement = str(replacementInt)
return replacement
else:
- self.logger.error("Start integer %s greater than end integer %s; will not replace" % (startInt, endInt) )
+ self.logger.error(
+ "Start integer %s greater than end integer %s; will not replace" % (startInt, endInt))
return old
elif floatMatch:
try:
@@ -301,7 +314,7 @@ def _getReplacement(self, old=None, earliestTime=None, latestTime=None, s=None,
significance = len(floatMatch.group(2))
if endFloat >= startFloat:
- floatret = round(random.uniform(startFloat,endFloat), significance)
+ floatret = round(random.uniform(startFloat, endFloat), significance)
if self.replacementType == 'rated':
rateFactor = 1.0
now = s.now()
@@ -310,7 +323,7 @@ def _getReplacement(self, old=None, earliestTime=None, latestTime=None, s=None,
rateFactor *= s.hourOfDayRate[str(now.hour)]
except KeyError:
import traceback
- stack = traceback.format_exc()
+ stack = traceback.format_exc()
self.logger.error("Hour of day rate failed for token %s. Stacktrace %s" % stack)
if type(s.dayOfWeekRate) == dict:
try:
@@ -322,13 +335,14 @@ def _getReplacement(self, old=None, earliestTime=None, latestTime=None, s=None,
rateFactor *= s.dayOfWeekRate[str(weekday)]
except KeyError:
import traceback
- stack = traceback.format_exc()
+ stack = traceback.format_exc()
self.logger.error("Day of week rate failed. Stacktrace %s" % stack)
floatret = round(floatret * rateFactor, significance)
floatret = str(floatret)
return floatret
else:
- self.logger.error("Start float %s greater than end float %s; will not replace" % (startFloat, endFloat))
+ self.logger.error(
+ "Start float %s greater than end float %s; will not replace" % (startFloat, endFloat))
return old
except ValueError:
self.logger.error("Could not parse float[%s:%s]" % (floatMatch.group(1), floatMatch.group(4)))
@@ -340,14 +354,16 @@ def _getReplacement(self, old=None, earliestTime=None, latestTime=None, s=None,
elif strLength > 0:
replacement = ''
while len(replacement) < strLength:
- ## Generate a random ASCII between dec 33->126
+ # Generate a random ASCII between dec 33->126
replacement += chr(random.randint(33, 126))
- ## Practice safe strings
+ # Practice safe strings
replacement = re.sub('%[0-9a-fA-F]+', '', urllib.quote(replacement))
-
+
return replacement
else:
- self.logger.error("Length specifier %s for string replacement must be greater than 0; will not replace" % (strLength) )
+ self.logger.error(
+ "Length specifier %s for string replacement must be greater than 0; will not replace" %
+ (strLength))
return old
elif hexMatch:
strLength = int(hexMatch.group(1))
@@ -367,29 +383,32 @@ def _getReplacement(self, old=None, earliestTime=None, latestTime=None, s=None,
return random.choice(value)
else:
- self.logger.error("Unknown replacement value '%s' for replacementType '%s'; will not replace" % (self.replacement, self.replacementType) )
+ self.logger.error("Unknown replacement value '%s' for replacementType '%s'; will not replace" %
+ (self.replacement, self.replacementType))
return old
elif self.replacementType in ('file', 'mvfile', 'seqfile'):
- if self._replacementFile != None:
+ if self._replacementFile is not None:
replacementFile = self._replacementFile
replacementColumn = self._replacementColumn
else:
try:
paths = self.replacement.split(':')
- if(len(paths) == 1):
+ if (len(paths) == 1):
replacementColumn = 0
else:
- try: # When it's not a mvfile, there's no number on the end:
+ try: # When it's not a mvfile, there's no number on the end:
replacementColumn = int(paths[-1])
except (ValueError):
replacementColumn = 0
- if(replacementColumn > 0):
+ if (replacementColumn > 0):
# This supports having a drive-letter colon
replacementFile = s.pathParser(":".join(paths[0:-1]))
else:
replacementFile = s.pathParser(self.replacement)
- except ValueError, e:
- self.logger.error("Replacement string '%s' improperly formatted. Should be /path/to/file or /path/to/file:column" % (self.replacement))
+ except ValueError:
+ self.logger.error(
+ "Replacement string '%s' improperly formatted. Should be /path/to/file or /path/to/file:column"
+ % self.replacement)
return old
self._replacementFile = replacementFile
self._replacementColumn = replacementColumn
@@ -399,18 +418,20 @@ def _getReplacement(self, old=None, earliestTime=None, latestTime=None, s=None,
# return the same random pick on every iteration
if replacementColumn > 0 and replacementFile in self.mvhash:
if replacementColumn > len(self.mvhash[replacementFile]):
- self.logger.error("Index for column '%s' in replacement file '%s' is out of bounds" % (replacementColumn, replacementFile))
+ self.logger.error("Index for column '%s' in replacement file '%s' is out of bounds" %
+ (replacementColumn, replacementFile))
return old
else:
# self.logger.debug("Returning mvhash: %s" % self.mvhash[replacementFile][replacementColumn-1])
- return self.mvhash[replacementFile][replacementColumn-1]
+ return self.mvhash[replacementFile][replacementColumn - 1]
else:
# Adding caching of the token file to avoid reading it every iteration
- if self._tokenfile != None:
+ if self._tokenfile is not None:
replacementLines = self._tokenfile
- ## Otherwise, lets read the file and build our cached results, pick a result and return it
+ # Otherwise, lets read the file and build our cached results, pick a result and return it
else:
- # self.logger.debug("replacementFile: %s replacementColumn: %s" % (replacementFile, replacementColumn))
+ # self.logger.debug("replacementFile: %s replacementColumn: %s" %
+ # (replacementFile, replacementColumn))
replacementFile = os.path.abspath(replacementFile)
self.logger.debug("Normalized replacement file %s" % replacementFile)
if os.path.exists(replacementFile) and os.path.isfile(replacementFile):
@@ -419,7 +440,7 @@ def _getReplacement(self, old=None, earliestTime=None, latestTime=None, s=None,
replacementFH.close()
if len(replacementLines) == 0:
- self.logger.error("Replacement file '%s' is empty; will not replace" % (replacementFile) )
+ self.logger.error("Replacement file '%s' is empty; will not replace" % (replacementFile))
return old
else:
self._tokenfile = replacementLines
@@ -432,16 +453,17 @@ def _getReplacement(self, old=None, earliestTime=None, latestTime=None, s=None,
self._tokenfilecounter += 1
else:
# pick value randomly from replacement file
- replacement = replacementLines[random.randint(0, len(replacementLines)-1)].strip()
+ replacement = replacementLines[random.randint(0, len(replacementLines) - 1)].strip()
if replacementColumn > 0:
self.mvhash[replacementFile] = replacement.split(',')
if replacementColumn > len(self.mvhash[replacementFile]):
- self.logger.error("Index for column '%s' in replacement file '%s' is out of bounds" % (replacementColumn, replacementFile))
+ self.logger.error("Index for column '%s' in replacement file '%s' is out of bounds" %
+ (replacementColumn, replacementFile))
return old
else:
- return self.mvhash[replacementFile][replacementColumn-1]
+ return self.mvhash[replacementFile][replacementColumn - 1]
else:
return replacement
elif self.replacementType == 'integerid':
@@ -450,5 +472,5 @@ def _getReplacement(self, old=None, earliestTime=None, latestTime=None, s=None,
return temp
else:
- self.logger.error("Unknown replacementType '%s'; will not replace" % (self.replacementType) )
- return old
\ No newline at end of file
+ self.logger.error("Unknown replacementType '%s'; will not replace" % self.replacementType)
+ return old
diff --git a/splunk_eventgen/lib/generatorplugin.py b/splunk_eventgen/lib/generatorplugin.py
index ebca83a2..6ab1ecac 100644
--- a/splunk_eventgen/lib/generatorplugin.py
+++ b/splunk_eventgen/lib/generatorplugin.py
@@ -1,15 +1,21 @@
from __future__ import division
+
+import datetime
import logging
import logging.handlers
import pprint
-import datetime
-from timeparser import timeParser
-import httplib2, urllib
+import time
+import random
+import urllib
from xml.dom import minidom
from xml.parsers.expat import ExpatError
+
+import httplib2
+
from eventgenoutput import Output
from eventgentimestamp import EventgenTimestamp
-import time
+from timeparser import timeParser
+
class GeneratorPlugin(object):
sampleLines = None
@@ -22,7 +28,7 @@ def __init__(self, sample):
def __str__(self):
"""Only used for debugging, outputs a pretty printed representation of this output"""
# Eliminate recursive going back to parent
- temp = dict([ (key, value) for (key, value) in self.__dict__.items() if key != '_c'])
+ # temp = dict([(key, value) for (key, value) in self.__dict__.items() if key != '_c'])
# return pprint.pformat(temp)
return ""
@@ -56,8 +62,8 @@ def build_events(self, eventsDict, startTime, earliest, latest, ignore_tokens=Fa
timeDiffFrac = "%d.%06d" % (timeDiff.seconds, timeDiff.microseconds)
self.logger.debug("Interval complete, flushing feed")
self._out.flush(endOfInterval=True)
- self.logger.debug("Generation of sample '%s' in app '%s' completed in %s seconds." % (
- self._sample.name, self._sample.app, timeDiffFrac))
+ self.logger.debug("Generation of sample '%s' in app '%s' completed in %s seconds." %
+ (self._sample.name, self._sample.app, timeDiffFrac))
except Exception as e:
self.logger.exception("Exception {} happened.".format(type(e)))
raise e
@@ -81,60 +87,66 @@ def updateConfig(self, config, outqueue):
def updateCounts(self, sample=None, count=None, start_time=None, end_time=None):
if sample:
- self._sample=sample
+ self._sample = sample
self.count = count
self.start_time = start_time
self.end_time = end_time
def setOutputMetadata(self, event):
- # self.logger.debug("Sample Index: %s Host: %s Source: %s Sourcetype: %s" % (self.index, self.host, self.source, self.sourcetype))
- # self.logger.debug("Event Index: %s Host: %s Source: %s Sourcetype: %s" % (sampleDict[x]['index'], sampleDict[x]['host'], sampleDict[x]['source'], sampleDict[x]['sourcetype']))
- if self._sample.sampletype == 'csv' and (event['index'] != self._sample.index or
- event['host'] != self._sample.host or
- event['source'] != self._sample.source or
- event['sourcetype'] != self._sample.sourcetype):
+ # self.logger.debug("Sample Index: %s Host: %s Source: %s Sourcetype: %s" %
+ # (self.index, self.host, self.source, self.sourcetype))
+ # self.logger.debug("Event Index: %s Host: %s Source: %s Sourcetype: %s" %
+ # (sampleDict[x]['index'], sampleDict[x]['host'], sampleDict[x]['source'],
+ # sampleDict[x]['sourcetype']))
+ if self._sample.sampletype == 'csv' and (event['index'] != self._sample.index
+ or event['host'] != self._sample.host
+ or event['source'] != self._sample.source
+ or event['sourcetype'] != self._sample.sourcetype):
self._sample.index = event['index']
self._sample.host = event['host']
# Allow randomizing the host:
- if(self._sample.hostToken):
+ if self._sample.hostToken:
self.host = self._sample.hostToken.replace(self.host)
self._sample.source = event['source']
self._sample.sourcetype = event['sourcetype']
- self.logger.debugv("Sampletype CSV. Setting CSV parameters. index: '%s' host: '%s' source: '%s' sourcetype: '%s'" \
- % (self._sample.index, self._sample.host, self._sample.source, self._sample.sourcetype))
+ self.logger.debug("Setting CSV parameters. index: '%s' host: '%s' source: '%s' sourcetype: '%s'" %
+ (self._sample.index, self._sample.host, self._sample.source, self._sample.sourcetype))
def setupBackfill(self):
- """Called by non-queueable plugins or by the timer to setup backfill times per config or based on a Splunk Search"""
+ """
+ Called by non-queueable plugins or by the timer to setup backfill times per config or based on a Splunk Search
+ """
s = self._sample
- if s.backfill != None:
+ if s.backfill is not None:
try:
s.backfillts = timeParser(s.backfill, timezone=s.timezone)
- self.logger.info("Setting up backfill of %s (%s)" % (s.backfill,s.backfillts))
+ self.logger.info("Setting up backfill of %s (%s)" % (s.backfill, s.backfillts))
except Exception as ex:
self.logger.error("Failed to parse backfill '%s': %s" % (s.backfill, ex))
raise
- if s.backfillSearch != None:
- if s.backfillSearchUrl == None:
+ if s.backfillSearch is not None:
+ if s.backfillSearchUrl is None:
try:
- s.backfillSearchUrl = c.getSplunkUrl(s)[0]
+ s.backfillSearchUrl = c.getSplunkUrl(s)[0] # noqa, we update c in the globals() dict
except ValueError:
- self.logger.error("Backfill Search URL not specified for sample '%s', not running backfill search" % s.name)
+ self.logger.error(
+ "Backfill Search URL not specified for sample '%s', not running backfill search" % s.name)
if not s.backfillSearch.startswith('search'):
s.backfillSearch = 'search ' + s.backfillSearch
s.backfillSearch += '| head 1 | table _time'
- if s.backfillSearchUrl != None:
- self.logger.debug("Searching Splunk URL '%s/services/search/jobs' with search '%s' with sessionKey '%s'" % (s.backfillSearchUrl, s.backfillSearch, s.sessionKey))
-
+ if s.backfillSearchUrl is not None:
+ self.logger.debug(
+ "Searching Splunk URL '%s/services/search/jobs' with search '%s' with sessionKey '%s'" %
+ (s.backfillSearchUrl, s.backfillSearch, s.sessionKey))
+
results = httplib2.Http(disable_ssl_certificate_validation=True).request(
- s.backfillSearchUrl + '/services/search/jobs',
- 'POST', headers={'Authorization': 'Splunk %s' % s.sessionKey},
- body=urllib.urlencode({'search': s.backfillSearch,
- 'earliest_time': s.backfill,
- 'exec_mode': 'oneshot'}))[1]
+ s.backfillSearchUrl + '/services/search/jobs', 'POST', headers={
+ 'Authorization': 'Splunk %s' % s.sessionKey}, body=urllib.urlencode({
+ 'search': s.backfillSearch, 'earliest_time': s.backfill, 'exec_mode': 'oneshot'}))[1]
try:
temptime = minidom.parseString(results).getElementsByTagName('text')[0].childNodes[0].nodeValue
# self.logger.debug("Time returned from backfill search: %s" % temptime)
@@ -145,8 +157,9 @@ def setupBackfill(self):
temptime = temptime.split('+')[0]
temptime = '-'.join(temptime.split('-')[0:3])
s.backfillts = datetime.datetime.strptime(temptime, '%Y-%m-%dT%H:%M:%S.%f')
- self.logger.debug("Backfill search results: '%s' value: '%s' time: '%s'" % (pprint.pformat(results), temptime, s.backfillts))
- except (ExpatError, IndexError):
+ self.logger.debug("Backfill search results: '%s' value: '%s' time: '%s'" %
+ (pprint.pformat(results), temptime, s.backfillts))
+ except (ExpatError, IndexError):
pass
if s.end is not None:
@@ -157,13 +170,14 @@ def setupBackfill(self):
parsed = True
except ValueError:
self.logger.debug("Failed to parse end '%s' for sample '%s', treating as end time" % (s.end, s.name))
-
- if not parsed:
+
+ if not parsed:
try:
s.endts = timeParser(s.end, timezone=s.timezone)
self.logger.info("Ending generation at %s (%s)" % (s.end, s.endts))
except Exception as ex:
- self.logger.error("Failed to parse end '%s' for sample '%s', treating as number of executions" % (s.end, s.name))
+ self.logger.error(
+ "Failed to parse end '%s' for sample '%s', treating as number of executions" % (s.end, s.name))
raise
def run(self, output_counter=None):
@@ -189,7 +203,7 @@ def replace_tokens(self, eventsDict, earliest, latest, ignore_tokens=False):
mvhash = {}
host = targetevent['host']
if hasattr(self._sample, "sequentialTimestamp") and self._sample.sequentialTimestamp and \
- self._sample.generator != 'perdayvolumegenerator':
+ self._sample.generator != 'perdayvolumegenerator':
pivot_timestamp = EventgenTimestamp.get_sequential_timestamp(earliest, latest, eventcount, total_count)
else:
pivot_timestamp = EventgenTimestamp.get_random_timestamp(earliest, latest)
@@ -212,14 +226,10 @@ def replace_tokens(self, eventsDict, earliest, latest, ignore_tokens=False):
time_val = int(time.mktime(pivot_timestamp.timetuple()))
except Exception:
time_val = int(time.mktime(self._sample.now().timetuple()))
- l = {'_raw': event,
- 'index': targetevent['index'],
- 'host': host,
- 'hostRegex': self._sample.hostRegex,
- 'source': targetevent['source'],
- 'sourcetype': targetevent['sourcetype'],
- '_time': time_val}
- send_events.append(l)
+ temp_event = {
+ '_raw': event, 'index': random.choice(self._sample.index_list)if len(self._sample.index_list) else targetevent['index'], 'host': host, 'hostRegex': self._sample.hostRegex,
+ 'source': targetevent['source'], 'sourcetype': targetevent['sourcetype'], '_time': time_val}
+ send_events.append(temp_event)
return send_events
diff --git a/splunk_eventgen/lib/logutils_src/doc/conf.py b/splunk_eventgen/lib/logutils_src/doc/conf.py
index 2f89fe54..17a8499c 100644
--- a/splunk_eventgen/lib/logutils_src/doc/conf.py
+++ b/splunk_eventgen/lib/logutils_src/doc/conf.py
@@ -14,7 +14,8 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
-import sys, os
+import os
+import sys
# If your extensions (or modules documented by autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
@@ -35,7 +36,7 @@
source_suffix = '.rst'
# The encoding of source files.
-#source_encoding = 'utf-8'
+# source_encoding = 'utf-8'
# The master toctree document.
master_doc = 'index'
@@ -55,39 +56,38 @@
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
-#language = None
+# language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
-#today = ''
+# today = ''
# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
+# today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
-#unused_docs = []
+# unused_docs = []
# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
+# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
+# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
-#add_module_names = True
+# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
-#show_authors = False
+# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
-
# Options for HTML output
# -----------------------
@@ -98,19 +98,19 @@
# The name for this set of Sphinx documents. If None, it defaults to
# " v documentation".
-#html_title = None
+# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
+# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
-#html_logo = None
+# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
-#html_favicon = None
+# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@@ -119,38 +119,38 @@
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
+# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
-#html_use_smartypants = True
+# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
+# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
-#html_additional_pages = {}
+# html_additional_pages = {}
# If false, no module index is generated.
-#html_use_modindex = True
+# html_use_modindex = True
# If false, no index is generated.
-#html_use_index = True
+# html_use_index = True
# If true, the index is split into individual pages for each letter.
-#html_split_index = False
+# html_split_index = False
# If true, the reST sources are included in the HTML build as _sources/.
-#html_copy_source = True
+# html_copy_source = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
+# html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = ''
+# html_file_suffix = ''
html_theme = os.environ.get('DOCS_THEME', 'alabaster')
html_theme_path = ['themes']
@@ -158,42 +158,37 @@
# Output file base name for HTML help builder.
htmlhelp_basename = 'Logutilsdoc'
-
# Options for LaTeX output
# ------------------------
# The paper size ('letter' or 'a4').
-#latex_paper_size = 'letter'
+# latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
-#latex_font_size = '10pt'
+# latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, document class [howto/manual]).
latex_documents = [
- ('index', 'Logutils.tex', ur'Logutils Documentation',
- ur'Vinay Sajip', 'manual'),
-]
+ ('index', 'Logutils.tex', ur'Logutils Documentation', ur'Vinay Sajip', 'manual'), ]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
-#latex_logo = None
+# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
-#latex_use_parts = False
+# latex_use_parts = False
# Additional stuff for the LaTeX preamble.
-#latex_preamble = ''
+# latex_preamble = ''
# Documents to append as an appendix to all manuals.
-#latex_appendices = []
+# latex_appendices = []
# If false, no module index is generated.
-#latex_use_modindex = True
-
+# latex_use_modindex = True
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
- 'http://docs.python.org/dev': None,
-}
+ 'http://docs.python.org/dev': None, }
diff --git a/splunk_eventgen/lib/logutils_src/logutils/__init__.py b/splunk_eventgen/lib/logutils_src/logutils/__init__.py
index 963c8df4..2811a987 100644
--- a/splunk_eventgen/lib/logutils_src/logutils/__init__.py
+++ b/splunk_eventgen/lib/logutils_src/logutils/__init__.py
@@ -15,6 +15,7 @@
__version__ = '0.3.4.1'
+
class NullHandler(logging.Handler):
"""
This handler does nothing. It's intended to be used to avoid the
@@ -48,6 +49,7 @@ def createLock(self):
"""
self.lock = None
+
class PercentStyle(object):
default_format = '%(message)s'
@@ -62,6 +64,7 @@ def usesTime(self):
def format(self, record):
return self._fmt % record.__dict__
+
class StrFormatStyle(PercentStyle):
default_format = '{message}'
asctime_format = '{asctime}'
@@ -85,11 +88,9 @@ def usesTime(self):
def format(self, record):
return self._tpl.substitute(**record.__dict__)
-_STYLES = {
- '%': PercentStyle,
- '{': StrFormatStyle,
- '$': StringTemplateStyle
-}
+
+_STYLES = {'%': PercentStyle, '{': StrFormatStyle, '$': StringTemplateStyle}
+
class Formatter(logging.Formatter):
"""
@@ -97,6 +98,7 @@ class Formatter(logging.Formatter):
3.2 Formatter behaviour with respect to allowing %-, {} or $-
formatting.
"""
+
def __init__(self, fmt=None, datefmt=None, style='%'):
"""
Initialize the formatter with specified format strings.
@@ -110,8 +112,7 @@ def __init__(self, fmt=None, datefmt=None, style='%'):
:class:`string.Template` formatting in your format string.
"""
if style not in _STYLES:
- raise ValueError('Style must be one of: %s' % ','.join(
- _STYLES.keys()))
+ raise ValueError('Style must be one of: %s' % ','.join(_STYLES.keys()))
self._style = _STYLES[style](fmt)
self._fmt = self._style._fmt
self.datefmt = datefmt
@@ -166,6 +167,7 @@ def __str__(self):
self.str = self.fmt.format(*self.args, **self.kwargs)
return self.str
+
class DollarMessage(object):
def __init__(self, fmt, **kwargs):
self.fmt = fmt
diff --git a/splunk_eventgen/lib/logutils_src/logutils/adapter.py b/splunk_eventgen/lib/logutils_src/logutils/adapter.py
index 92706c0f..220c188d 100644
--- a/splunk_eventgen/lib/logutils_src/logutils/adapter.py
+++ b/splunk_eventgen/lib/logutils_src/logutils/adapter.py
@@ -2,8 +2,10 @@
# Copyright (C) 2010-2017 Vinay Sajip. See LICENSE.txt for details.
#
import logging
+
import logutils
+
class LoggerAdapter(object):
"""
An adapter for loggers which makes it easier to specify contextual
diff --git a/splunk_eventgen/lib/logutils_src/logutils/colorize.py b/splunk_eventgen/lib/logutils_src/logutils/colorize.py
index f95c0366..8f375e5d 100644
--- a/splunk_eventgen/lib/logutils_src/logutils/colorize.py
+++ b/splunk_eventgen/lib/logutils_src/logutils/colorize.py
@@ -10,6 +10,7 @@
except NameError:
unicode = None
+
class ColorizingStreamHandler(logging.StreamHandler):
"""
A stream handler which supports colorizing of console streams
@@ -28,18 +29,16 @@ class ColorizingStreamHandler(logging.StreamHandler):
'blue': 4,
'magenta': 5,
'cyan': 6,
- 'white': 7,
- }
+ 'white': 7, }
- #levels to (background, foreground, bold/intense)
+ # levels to (background, foreground, bold/intense)
if os.name == 'nt':
level_map = {
logging.DEBUG: (None, 'blue', True),
logging.INFO: (None, 'white', False),
logging.WARNING: (None, 'yellow', True),
logging.ERROR: (None, 'red', True),
- logging.CRITICAL: ('red', 'white', True),
- }
+ logging.CRITICAL: ('red', 'white', True), }
else:
"Maps levels to colour/intensity settings."
level_map = {
@@ -47,8 +46,7 @@ class ColorizingStreamHandler(logging.StreamHandler):
logging.INFO: (None, 'black', False),
logging.WARNING: (None, 'yellow', False),
logging.ERROR: (None, 'red', False),
- logging.CRITICAL: ('red', 'white', True),
- }
+ logging.CRITICAL: ('red', 'white', True), }
csi = '\x1b['
reset = '\x1b[0m'
@@ -78,6 +76,7 @@ def emit(self, record):
self.handleError(record)
if os.name != 'nt':
+
def output_colorized(self, message):
"""
Output a colorized message.
@@ -98,14 +97,14 @@ def output_colorized(self, message):
ansi_esc = re.compile(r'\x1b\[((?:\d+)(?:;(?:\d+))*)m')
nt_color_map = {
- 0: 0x00, # black
- 1: 0x04, # red
- 2: 0x02, # green
- 3: 0x06, # yellow
- 4: 0x01, # blue
- 5: 0x05, # magenta
- 6: 0x03, # cyan
- 7: 0x07, # white
+ 0: 0x00, # black
+ 1: 0x04, # red
+ 2: 0x02, # green
+ 3: 0x06, # yellow
+ 4: 0x01, # blue
+ 5: 0x05, # magenta
+ 6: 0x03, # cyan
+ 7: 0x07, # white
}
def output_colorized(self, message):
@@ -128,7 +127,7 @@ def output_colorized(self, message):
fd = getattr(self.stream, 'fileno', None)
if fd is not None:
fd = fd()
- if fd in (1, 2): # stdout or stderr
+ if fd in (1, 2): # stdout or stderr
h = ctypes.windll.kernel32.GetStdHandle(-10 - fd)
while parts:
text = parts.pop(0)
@@ -145,11 +144,11 @@ def output_colorized(self, message):
elif 30 <= p <= 37:
color |= self.nt_color_map[p - 30]
elif p == 1:
- color |= 0x08 # foreground intensity on
- elif p == 0: # reset to default color
+ color |= 0x08 # foreground intensity on
+ elif p == 0: # reset to default color
color = 0x07
else:
- pass # error condition ignored
+ pass # error condition ignored
ctypes.windll.kernel32.SetConsoleTextAttribute(h, color)
def colorize(self, message, record):
@@ -173,8 +172,7 @@ def colorize(self, message, record):
if bold:
params.append('1')
if params:
- message = ''.join((self.csi, ';'.join(params),
- 'm', message, self.reset))
+ message = ''.join((self.csi, ';'.join(params), 'm', message, self.reset))
return message
def format(self, record):
diff --git a/splunk_eventgen/lib/logutils_src/logutils/dictconfig.py b/splunk_eventgen/lib/logutils_src/logutils/dictconfig.py
index c774552e..26b8886e 100644
--- a/splunk_eventgen/lib/logutils_src/logutils/dictconfig.py
+++ b/splunk_eventgen/lib/logutils_src/logutils/dictconfig.py
@@ -4,7 +4,6 @@
import logging.handlers
import re
import sys
-import types
try:
basestring
@@ -17,18 +16,21 @@
IDENTIFIER = re.compile('^[a-z_][a-z0-9_]*$', re.I)
+
def valid_ident(s):
m = IDENTIFIER.match(s)
if not m:
raise ValueError('Not a valid Python identifier: %r' % s)
return True
+
#
# This function is defined in logging only in recent versions of Python
#
try:
from logging import _checkLevel
except ImportError:
+
def _checkLevel(level):
if isinstance(level, int):
rv = level
@@ -41,10 +43,10 @@ def _checkLevel(level):
raise ValueError('Unknown level: %r' % level)
rv = levelnames[level]
else:
- raise TypeError('Level not an integer or a '
- 'valid string: %r' % level)
+ raise TypeError('Level not an integer or a ' 'valid string: %r' % level)
return rv
+
# The ConvertingXXX classes are wrappers around standard Python containers,
# and they serve to convert any suitable values in the container. The
# conversion converts base dicts, lists and tuples to their wrapped
@@ -54,17 +56,17 @@ def _checkLevel(level):
# Each wrapper should have a configurator attribute holding the actual
# configurator to use for conversion.
+
class ConvertingDict(dict):
"""A converting dictionary wrapper."""
def __getitem__(self, key):
value = dict.__getitem__(self, key)
result = self.configurator.convert(value)
- #If the converted value is different, save for next time
+ # If the converted value is different, save for next time
if value is not result:
self[key] = result
- if type(result) in (ConvertingDict, ConvertingList,
- ConvertingTuple):
+ if type(result) in (ConvertingDict, ConvertingList, ConvertingTuple):
result.parent = self
result.key = key
return result
@@ -72,11 +74,10 @@ def __getitem__(self, key):
def get(self, key, default=None):
value = dict.get(self, key, default)
result = self.configurator.convert(value)
- #If the converted value is different, save for next time
+ # If the converted value is different, save for next time
if value is not result:
self[key] = result
- if type(result) in (ConvertingDict, ConvertingList,
- ConvertingTuple):
+ if type(result) in (ConvertingDict, ConvertingList, ConvertingTuple):
result.parent = self
result.key = key
return result
@@ -85,22 +86,22 @@ def pop(self, key, default=None):
value = dict.pop(self, key, default)
result = self.configurator.convert(value)
if value is not result:
- if type(result) in (ConvertingDict, ConvertingList,
- ConvertingTuple):
+ if type(result) in (ConvertingDict, ConvertingList, ConvertingTuple):
result.parent = self
result.key = key
return result
+
class ConvertingList(list):
"""A converting list wrapper."""
+
def __getitem__(self, key):
value = list.__getitem__(self, key)
result = self.configurator.convert(value)
- #If the converted value is different, save for next time
+ # If the converted value is different, save for next time
if value is not result:
self[key] = result
- if type(result) in (ConvertingDict, ConvertingList,
- ConvertingTuple):
+ if type(result) in (ConvertingDict, ConvertingList, ConvertingTuple):
result.parent = self
result.key = key
return result
@@ -109,23 +110,24 @@ def pop(self, idx=-1):
value = list.pop(self, idx)
result = self.configurator.convert(value)
if value is not result:
- if type(result) in (ConvertingDict, ConvertingList,
- ConvertingTuple):
+ if type(result) in (ConvertingDict, ConvertingList, ConvertingTuple):
result.parent = self
return result
+
class ConvertingTuple(tuple):
"""A converting tuple wrapper."""
+
def __getitem__(self, key):
value = tuple.__getitem__(self, key)
result = self.configurator.convert(value)
if value is not result:
- if type(result) in (ConvertingDict, ConvertingList,
- ConvertingTuple):
+ if type(result) in (ConvertingDict, ConvertingList, ConvertingTuple):
result.parent = self
result.key = key
return result
+
class BaseConfigurator(object):
"""
The configurator base class which defines some useful defaults.
@@ -139,9 +141,8 @@ class BaseConfigurator(object):
DIGIT_PATTERN = re.compile(r'^\d+$')
value_converters = {
- 'ext' : 'ext_convert',
- 'cfg' : 'cfg_convert',
- }
+ 'ext': 'ext_convert',
+ 'cfg': 'cfg_convert', }
# We might want to use a different one, e.g. importlib
importer = __import__
@@ -191,7 +192,6 @@ def cfg_convert(self, value):
else:
rest = rest[m.end():]
d = self.config[m.groups()[0]]
- #print d, rest
while rest:
m = self.DOT_PATTERN.match(rest)
if m:
@@ -204,16 +204,15 @@ def cfg_convert(self, value):
d = d[idx]
else:
try:
- n = int(idx) # try as number first (most likely)
+ n = int(idx) # try as number first (most likely)
d = d[n]
except TypeError:
d = d[idx]
if m:
rest = rest[m.end():]
else:
- raise ValueError('Unable to convert '
- '%r at %r' % (value, rest))
- #rest should be empty
+ raise ValueError('Unable to convert ' '%r at %r' % (value, rest))
+ # rest should be empty
return d
def convert(self, value):
@@ -228,8 +227,7 @@ def convert(self, value):
elif not isinstance(value, ConvertingList) and isinstance(value, list):
value = ConvertingList(value)
value.configurator = self
- elif not isinstance(value, ConvertingTuple) and\
- isinstance(value, tuple):
+ elif not isinstance(value, ConvertingTuple) and isinstance(value, tuple):
value = ConvertingTuple(value)
value.configurator = self
elif isinstance(value, basestring):
@@ -264,6 +262,7 @@ def as_tuple(self, value):
value = tuple(value)
return value
+
def named_handlers_supported():
major, minor = sys.version_info[:2]
if major == 2:
@@ -274,6 +273,7 @@ def named_handlers_supported():
result = (major > 3)
return result
+
class DictConfigurator(BaseConfigurator):
"""
Configure logging using a dictionary-like object to describe the
@@ -299,8 +299,7 @@ def configure(self):
if named_handlers_supported():
for name in handlers:
if name not in logging._handlers:
- raise ValueError('No handler found with '
- 'name %r' % name)
+ raise ValueError('No handler found with ' 'name %r' % name)
else:
try:
handler = logging._handlers[name]
@@ -310,24 +309,21 @@ def configure(self):
handler.setLevel(_checkLevel(level))
except StandardError:
e = sys.exc_info()[1]
- raise ValueError('Unable to configure handler '
- '%r: %s' % (name, e))
+ raise ValueError('Unable to configure handler ' '%r: %s' % (name, e))
loggers = config.get('loggers', EMPTY_DICT)
for name in loggers:
try:
self.configure_logger(name, loggers[name], True)
except StandardError:
e = sys.exc_info()[1]
- raise ValueError('Unable to configure logger '
- '%r: %s' % (name, e))
+ raise ValueError('Unable to configure logger ' '%r: %s' % (name, e))
root = config.get('root', None)
if root:
try:
self.configure_root(root, True)
except StandardError:
e = sys.exc_info()[1]
- raise ValueError('Unable to configure root '
- 'logger: %s' % e)
+ raise ValueError('Unable to configure root ' 'logger: %s' % e)
else:
disable_existing = config.pop('disable_existing_loggers', True)
@@ -338,12 +334,10 @@ def configure(self):
formatters = config.get('formatters', EMPTY_DICT)
for name in formatters:
try:
- formatters[name] = self.configure_formatter(
- formatters[name])
+ formatters[name] = self.configure_formatter(formatters[name])
except StandardError:
e = sys.exc_info()[1]
- raise ValueError('Unable to configure '
- 'formatter %r: %s' % (name, e))
+ raise ValueError('Unable to configure ' 'formatter %r: %s' % (name, e))
# Next, do filters - they don't refer to anything else, either
filters = config.get('filters', EMPTY_DICT)
for name in filters:
@@ -351,8 +345,7 @@ def configure(self):
filters[name] = self.configure_filter(filters[name])
except StandardError:
e = sys.exc_info()[1]
- raise ValueError('Unable to configure '
- 'filter %r: %s' % (name, e))
+ raise ValueError('Unable to configure ' 'filter %r: %s' % (name, e))
# Next, do handlers - they refer to formatters and filters
# As handlers can refer to other handlers, sort the keys
@@ -365,28 +358,20 @@ def configure(self):
handlers[name] = handler
except StandardError:
e = sys.exc_info()[1]
- raise ValueError('Unable to configure handler '
- '%r: %s' % (name, e))
+ raise ValueError('Unable to configure handler ' '%r: %s' % (name, e))
# Next, do loggers - they refer to handlers and filters
- #we don't want to lose the existing loggers,
- #since other threads may have pointers to them.
- #existing is set to contain all existing loggers,
- #and as we go through the new configuration we
- #remove any which are configured. At the end,
- #what's left in existing is the set of loggers
- #which were in the previous configuration but
- #which are not in the new configuration.
+ # We don't want to lose the existing loggers, since other threads may have pointers to them.
+ # Existing is set to contain all existing loggers, and as we go through the new configuration we
+ # remove any which are configured. At the end, what's left in existing is the set of loggers
+ # which were in the previous configuration but which are not in the new configuration.
root = logging.root
existing = sorted(root.manager.loggerDict.keys())
- #The list needs to be sorted so that we can
- #avoid disabling child loggers of explicitly
- #named loggers. With a sorted list it is easier
- #to find the child loggers.
- #We'll keep the list of existing loggers
- #which are children of named loggers here...
+ # The list needs to be sorted so that we can avoid disabling child loggers of explicitly named loggers.
+ # With a sorted list it is easier to find the child loggers. We'll keep the list of existing loggers
+ # which are children of named loggers here...
child_loggers = []
- #now set up the new ones...
+ # now set up the new ones...
loggers = config.get('loggers', EMPTY_DICT)
for name in loggers:
if name in existing:
@@ -394,7 +379,7 @@ def configure(self):
prefixed = name + "."
pflen = len(prefixed)
num_existing = len(existing)
- i = i + 1 # look at the entry after name
+ i = i + 1 # look at the entry after name
while (i < num_existing) and\
(existing[i][:pflen] == prefixed):
child_loggers.append(existing[i])
@@ -404,14 +389,11 @@ def configure(self):
self.configure_logger(name, loggers[name])
except StandardError:
e = sys.exc_info()[1]
- raise ValueError('Unable to configure logger '
- '%r: %s' % (name, e))
-
- #Disable any old loggers. There's no point deleting
- #them as other threads may continue to hold references
- #and by disabling them, you stop them doing any logging.
- #However, don't disable children of named loggers, as that's
- #probably not what was intended by the user.
+ raise ValueError('Unable to configure logger ' '%r: %s' % (name, e))
+
+ # Disable any old loggers. There's no point deleting them as other threads may continue to hold
+ # references and by disabling them, you stop them doing any logging. However, don't disable children of
+ # named loggers, as that's probably not what was intended by the user.
for log in existing:
logger = root.manager.loggerDict[log]
if log in child_loggers:
@@ -428,25 +410,22 @@ def configure(self):
self.configure_root(root)
except StandardError:
e = sys.exc_info()[1]
- raise ValueError('Unable to configure root '
- 'logger: %s' % e)
+ raise ValueError('Unable to configure root ' 'logger: %s' % e)
finally:
logging._releaseLock()
def configure_formatter(self, config):
"""Configure a formatter from a dictionary."""
if '()' in config:
- factory = config['()'] # for use in exception handler
+ factory = config['()'] # for use in exception handler
try:
result = self.configure_custom(config)
except TypeError:
te = sys.exc_info()[1]
if "'format'" not in str(te):
raise
- #Name of parameter changed from fmt to format.
- #Retry with old name.
- #This is so that code can be used with older Python versions
- #(e.g. by Django)
+ # Name of parameter changed from fmt to format. Retry with old name. This is so that code can be used
+ # with older Python versions (e.g. by Django)
config['fmt'] = config.pop('format')
config['()'] = factory
result = self.configure_custom(config)
@@ -482,8 +461,7 @@ def configure_handler(self, config):
formatter = self.config['formatters'][formatter]
except StandardError:
e = sys.exc_info()[1]
- raise ValueError('Unable to set formatter '
- '%r: %s' % (formatter, e))
+ raise ValueError('Unable to set formatter ' '%r: %s' % (formatter, e))
level = config.pop('level', None)
filters = config.pop('filters', None)
if '()' in config:
@@ -493,20 +471,16 @@ def configure_handler(self, config):
factory = c
else:
klass = self.resolve(config.pop('class'))
- #Special case for handler which refers to another handler
- if issubclass(klass, logging.handlers.MemoryHandler) and\
- 'target' in config:
+ # Special case for handler which refers to another handler
+ if issubclass(klass, logging.handlers.MemoryHandler) and 'target' in config:
try:
config['target'] = self.config['handlers'][config['target']]
except StandardError:
e = sys.exc_info()[1]
- raise ValueError('Unable to set target handler '
- '%r: %s' % (config['target'], e))
- elif issubclass(klass, logging.handlers.SMTPHandler) and\
- 'mailhost' in config:
+ raise ValueError('Unable to set target handler ' '%r: %s' % (config['target'], e))
+ elif issubclass(klass, logging.handlers.SMTPHandler) and 'mailhost' in config:
config['mailhost'] = self.as_tuple(config['mailhost'])
- elif issubclass(klass, logging.handlers.SysLogHandler) and\
- 'address' in config:
+ elif issubclass(klass, logging.handlers.SysLogHandler) and 'address' in config:
config['address'] = self.as_tuple(config['address'])
factory = klass
kwargs = dict([(k, config[k]) for k in config if valid_ident(k)])
@@ -516,10 +490,8 @@ def configure_handler(self, config):
te = sys.exc_info()[1]
if "'stream'" not in str(te):
raise
- #The argument name changed from strm to stream
- #Retry with old name.
- #This is so that code can be used with older Python versions
- #(e.g. by Django)
+ # The argument name changed from strm to stream, so we retry with the old name. This is so that code can be
+ # used with older Python versions (e.g. by Django)
kwargs['strm'] = kwargs.pop('stream')
result = factory(**kwargs)
if formatter:
@@ -547,7 +519,7 @@ def common_logger_config(self, logger, config, incremental=False):
if level is not None:
logger.setLevel(_checkLevel(level))
if not incremental:
- #Remove any existing handlers
+ # Remove any existing handlers
for h in logger.handlers[:]:
logger.removeHandler(h)
handlers = config.get('handlers', None)
@@ -570,8 +542,10 @@ def configure_root(self, config, incremental=False):
root = logging.getLogger()
self.common_logger_config(root, config, incremental)
+
dictConfigClass = DictConfigurator
+
def dictConfig(config):
"""Configure logging using a dictionary."""
dictConfigClass(config).configure()
diff --git a/splunk_eventgen/lib/logutils_src/logutils/http.py b/splunk_eventgen/lib/logutils_src/logutils/http.py
index d1fe99d3..2d59dc88 100644
--- a/splunk_eventgen/lib/logutils_src/logutils/http.py
+++ b/splunk_eventgen/lib/logutils_src/logutils/http.py
@@ -3,6 +3,7 @@
#
import logging
+
class HTTPHandler(logging.Handler):
"""
A class which sends records to a Web server, using either GET or
@@ -18,6 +19,7 @@ class HTTPHandler(logging.Handler):
to avoid sending usernames and passwords in
cleartext over the wire.
"""
+
def __init__(self, host, url, method="GET", secure=False, credentials=None):
"""
Initialize an instance.
@@ -51,7 +53,8 @@ def emit(self, record):
:param record: The record to be emitted.
"""
try:
- import http.client, urllib.parse
+ import http.client
+ import urllib.parse
host = self.host
if self.secure:
h = http.client.HTTPSConnection(host)
@@ -73,8 +76,7 @@ def emit(self, record):
host = host[:i]
h.putheader("Host", host)
if self.method == "POST":
- h.putheader("Content-type",
- "application/x-www-form-urlencoded")
+ h.putheader("Content-type", "application/x-www-form-urlencoded")
h.putheader("Content-length", str(len(data)))
if self.credentials:
import base64
@@ -82,7 +84,7 @@ def emit(self, record):
s = 'Basic ' + base64.b64encode(s).strip()
h.putheader('Authorization', s)
h.endheaders(data if self.method == "POST" else None)
- h.getresponse() #can't do anything with the result
+ h.getresponse() # can't do anything with the result
except (KeyboardInterrupt, SystemExit):
raise
except:
diff --git a/splunk_eventgen/lib/logutils_src/logutils/queue.py b/splunk_eventgen/lib/logutils_src/logutils/queue.py
index fea91d8d..0a7d22a2 100644
--- a/splunk_eventgen/lib/logutils_src/logutils/queue.py
+++ b/splunk_eventgen/lib/logutils_src/logutils/queue.py
@@ -20,11 +20,13 @@
version here is for use with earlier Python versions.
"""
import logging
+import threading
+
try:
import Queue as queue
except ImportError:
import queue
-import threading
+
class QueueHandler(logging.Handler):
"""
@@ -97,6 +99,7 @@ def emit(self, record):
except:
self.handleError(record)
+
class QueueListener(object):
"""
This class implements an internal threaded listener which watches for
@@ -144,7 +147,7 @@ def start(self):
t.setDaemon(True)
t.start()
- def prepare(self , record):
+ def prepare(self, record):
"""
Prepare a record for handling.
diff --git a/splunk_eventgen/lib/logutils_src/logutils/redis.py b/splunk_eventgen/lib/logutils_src/logutils/redis.py
index a8ead302..46641bf2 100644
--- a/splunk_eventgen/lib/logutils_src/logutils/redis.py
+++ b/splunk_eventgen/lib/logutils_src/logutils/redis.py
@@ -6,11 +6,13 @@
"""
from logutils.queue import QueueHandler, QueueListener
+
try:
import cPickle as pickle
except ImportError:
import pickle
+
class RedisQueueHandler(QueueHandler):
"""
A QueueHandler implementation which pushes pickled
@@ -23,6 +25,7 @@ class RedisQueueHandler(QueueHandler):
:param limit: If specified, the queue is restricted to
have only this many elements.
"""
+
def __init__(self, key='python.logging', redis=None, limit=0):
if redis is None:
from redis import Redis
@@ -38,6 +41,7 @@ def enqueue(self, record):
if self.limit:
self.queue.ltrim(self.key, -self.limit, -1)
+
class RedisQueueListener(QueueListener):
"""
A QueueListener implementation which fetches pickled
@@ -48,6 +52,7 @@ class RedisQueueListener(QueueListener):
:param redis: If specified, this instance is used to
communicate with a Redis instance.
"""
+
def __init__(self, *handlers, **kwargs):
redis = kwargs.get('redis')
if redis is None:
diff --git a/splunk_eventgen/lib/logutils_src/logutils/testing.py b/splunk_eventgen/lib/logutils_src/logutils/testing.py
index 3c612179..bb8ac3df 100644
--- a/splunk_eventgen/lib/logutils_src/logutils/testing.py
+++ b/splunk_eventgen/lib/logutils_src/logutils/testing.py
@@ -1,9 +1,9 @@
#
# Copyright (C) 2010-2017 Vinay Sajip. See LICENSE.txt for details.
#
-import logging
from logging.handlers import BufferingHandler
+
class TestHandler(BufferingHandler):
"""
This handler collects records in a buffer for later inspection by
@@ -12,6 +12,7 @@ class TestHandler(BufferingHandler):
:param matcher: The :class:`~logutils.testing.Matcher` instance to
use for matching.
"""
+
def __init__(self, matcher):
# BufferingHandler takes a "capacity" argument
# so as to know when to flush. As we're overriding
@@ -64,8 +65,8 @@ def matches(self, **kwargs):
if self.matcher.matches(d, **kwargs):
result = True
break
- #if not result:
- # print('*** matcher failed completely on %d records' % len(self.buffer))
+ # if not result:
+ # print('*** matcher failed completely on %d records' % len(self.buffer))
return result
def matchall(self, kwarglist):
@@ -96,6 +97,7 @@ def count(self):
"""
return len(self.buffer)
+
class Matcher(object):
"""
This utility class matches a stored dictionary of
@@ -129,7 +131,7 @@ def matches(self, d, **kwargs):
v = kwargs[k]
dv = d.get(k)
if not self.match_value(k, dv, v):
- #print('*** matcher failed: %s, %r, %r' % (k, dv, v))
+ # print('*** matcher failed: %s, %r, %r' % (k, dv, v))
result = False
break
return result
@@ -150,6 +152,6 @@ def match_value(self, k, dv, v):
result = (v == dv)
else:
result = dv.find(v) >= 0
- #if not result:
+ # if not result:
# print('*** matcher failed on %s: %r vs. %r' % (k, dv, v))
return result
diff --git a/splunk_eventgen/lib/logutils_src/logutils_src_setup.py b/splunk_eventgen/lib/logutils_src/logutils_src_setup.py
index f0891d65..8eb90944 100644
--- a/splunk_eventgen/lib/logutils_src/logutils_src_setup.py
+++ b/splunk_eventgen/lib/logutils_src/logutils_src_setup.py
@@ -1,9 +1,10 @@
# -*- coding: utf-8 -*-
import distutils.core
-import logutils
-from os.path import join, dirname, abspath
import re
+from os.path import dirname, join
+
+import logutils
def description():
@@ -16,6 +17,7 @@ def description():
avail, = re.findall(regexp, readme, re.DOTALL)
return reqts + avail
+
class TestCommand(distutils.core.Command):
user_options = []
@@ -37,6 +39,7 @@ def initialize_options(self):
def finalize_options(self):
pass
+
distutils.core.setup(
name='logutils',
version=logutils.__version__,
@@ -44,7 +47,7 @@ def finalize_options(self):
author_email='vinay_sajip@red-dove.com',
url='http://code.google.com/p/logutils/',
description='Logging utilities',
- long_description = description(),
+ long_description=description(),
license='Copyright (C) 2010-2017 by Vinay Sajip. All Rights Reserved. See LICENSE.txt for license.',
classifiers=[
'Development Status :: 5 - Production/Stable',
@@ -55,11 +58,8 @@ def finalize_options(self):
'Programming Language :: Python',
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 3",
- 'Topic :: Software Development',
- ],
+ 'Topic :: Software Development', ],
packages=['logutils'],
cmdclass={
- 'test': TestCommand,
- },
-
+ 'test': TestCommand, },
)
diff --git a/splunk_eventgen/lib/logutils_src/tests/logutil_tests.py b/splunk_eventgen/lib/logutils_src/tests/logutil_tests.py
deleted file mode 100644
index e86d1062..00000000
--- a/splunk_eventgen/lib/logutils_src/tests/logutil_tests.py
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Copyright (C) 2008-2017 Vinay Sajip. See LICENSE.txt for details.
-#
-import sys
-from test_testing import LoggingTest
-from test_dictconfig import ConfigDictTest
-from test_queue import QueueTest
-from test_formatter import FormatterTest
-from test_messages import MessageTest
-from test_colorize import ColorizeTest
-try:
- from test_redis import RedisQueueTest
-except ImportError:
- pass
-
-# The adapter won't work in < 2.5 because the "extra" parameter used by it
-# only appeared in 2.5 :-(
-if sys.version_info[:2] >= (2, 5):
- from test_adapter import AdapterTest
-else:
- print("LoggerAdapter won't work in Python < 2.5, so its tests are being "
- "skipped.")
diff --git a/splunk_eventgen/lib/logutils_src/tests/mytest.py b/splunk_eventgen/lib/logutils_src/tests/mytest.py
index a5f40d32..ac9cbcc2 100644
--- a/splunk_eventgen/lib/logutils_src/tests/mytest.py
+++ b/splunk_eventgen/lib/logutils_src/tests/mytest.py
@@ -1,6 +1,7 @@
from __future__ import absolute_import
-from logutils.testing import TestHandler, Matcher
+from logutils.testing import Matcher, TestHandler
+
class MyTestHandler(TestHandler):
def __init__(self):
diff --git a/splunk_eventgen/lib/logutils_src/tests/test_adapter.py b/splunk_eventgen/lib/logutils_src/tests/test_adapter.py
index d29bd106..a827f95d 100644
--- a/splunk_eventgen/lib/logutils_src/tests/test_adapter.py
+++ b/splunk_eventgen/lib/logutils_src/tests/test_adapter.py
@@ -2,23 +2,25 @@
# Copyright (C) 2008-2017 Vinay Sajip. See LICENSE.txt for details.
#
import logging
-from logutils.adapter import LoggerAdapter
-from logutils.testing import TestHandler, Matcher
import unittest
+from logutils.adapter import LoggerAdapter
+from logutils.testing import Matcher, TestHandler
+
+
class AdapterTest(unittest.TestCase):
def setUp(self):
self.handler = h = TestHandler(Matcher())
- self.logger = l = logging.getLogger()
- l.addHandler(h)
- self.adapter = LoggerAdapter(l, {})
+ self.logger = temp_logger = logging.getLogger()
+ temp_logger.addHandler(h)
+ self.adapter = LoggerAdapter(temp_logger, {})
def tearDown(self):
self.logger.removeHandler(self.handler)
self.handler.close()
def test_simple(self):
- "Simple test of logging test harness."
+ """Simple test of logging test harness."""
# Just as a demo, let's log some messages.
# Only one should show up in the log.
self.adapter.debug("This won't show up.")
@@ -30,20 +32,20 @@ def test_simple(self):
self.assertFalse(h.matches(levelno=logging.INFO))
def test_partial(self):
- "Test of partial matching in logging test harness."
+ """Test of partial matching in logging test harness."""
# Just as a demo, let's log some messages.
# Only one should show up in the log.
self.adapter.debug("This won't show up.")
self.adapter.info("Neither will this.")
self.adapter.warning("But this will.")
h = self.handler
- self.assertTrue(h.matches(msg="ut th")) # from "But this will"
- self.assertTrue(h.matches(message="ut th")) # from "But this will"
+ self.assertTrue(h.matches(msg="ut th")) # from "But this will"
+ self.assertTrue(h.matches(message="ut th")) # from "But this will"
self.assertFalse(h.matches(message="either"))
self.assertFalse(h.matches(message="won't"))
def test_multiple(self):
- "Test of matching multiple values in logging test harness."
+ """Test of matching multiple values in logging test harness."""
# Just as a demo, let's log some messages.
# Only one should show up in the log.
self.adapter.debug("This won't show up.")
@@ -51,19 +53,18 @@ def test_multiple(self):
self.adapter.warning("But this will.")
self.adapter.error("And so will this.")
h = self.handler
- self.assertTrue(h.matches(levelno=logging.WARNING,
- message='ut th'))
- self.assertTrue(h.matches(levelno=logging.ERROR,
- message='nd so w'))
+ self.assertTrue(h.matches(levelno=logging.WARNING, message='ut th'))
+ self.assertTrue(h.matches(levelno=logging.ERROR, message='nd so w'))
self.assertFalse(h.matches(levelno=logging.INFO))
def test_hashandlers(self):
- "Test of hasHandlers() functionality."
+ """Test of hasHandlers() functionality."""
self.assertTrue(self.adapter.hasHandlers())
self.logger.removeHandler(self.handler)
self.assertFalse(self.adapter.hasHandlers())
self.logger.addHandler(self.handler)
self.assertTrue(self.adapter.hasHandlers())
+
if __name__ == '__main__':
unittest.main()
diff --git a/splunk_eventgen/lib/logutils_src/tests/test_colorize.py b/splunk_eventgen/lib/logutils_src/tests/test_colorize.py
index 022b6318..18d1b263 100644
--- a/splunk_eventgen/lib/logutils_src/tests/test_colorize.py
+++ b/splunk_eventgen/lib/logutils_src/tests/test_colorize.py
@@ -2,18 +2,18 @@
# Copyright (C) 2012-2017 Vinay Sajip. See LICENSE.txt for details.
#
import logging
-import logutils.colorize
-import os
import sys
import unittest
+import logutils.colorize
+
if sys.version_info[0] < 3:
u = lambda o: unicode(o, 'unicode_escape')
else:
u = lambda o: o
-class ColorizeTest(unittest.TestCase):
+class ColorizeTest(unittest.TestCase):
def test_colorize(self):
logger = logging.getLogger()
handler = logutils.colorize.ColorizingStreamHandler()
diff --git a/splunk_eventgen/lib/logutils_src/tests/test_dictconfig.py b/splunk_eventgen/lib/logutils_src/tests/test_dictconfig.py
index 3aee9841..950bcc6c 100644
--- a/splunk_eventgen/lib/logutils_src/tests/test_dictconfig.py
+++ b/splunk_eventgen/lib/logutils_src/tests/test_dictconfig.py
@@ -2,41 +2,47 @@
# Copyright 2009-2017 by Vinay Sajip. See LICENSE.txt for details.
#
import logging
+import unittest
+
from logutils.adapter import LoggerAdapter
from logutils.dictconfig import dictConfig, named_handlers_supported
-from logutils.testing import TestHandler, Matcher
-import sys
-import unittest
+from logutils.testing import Matcher, TestHandler
try:
StandardError
except NameError:
StandardError = Exception
+
class ExceptionFormatter(logging.Formatter):
"""A special exception formatter."""
+
def formatException(self, ei):
return "Got a [%s]" % ei[0].__name__
+
def formatFunc(format, datefmt=None):
return logging.Formatter(format, datefmt)
+
def testHandler():
return TestHandler(Matcher())
+
def handlerFunc():
return logging.StreamHandler()
+
class CustomHandler(logging.StreamHandler):
pass
-class ConfigDictTest(unittest.TestCase):
+class ConfigDictTest(unittest.TestCase):
"""Reading logging config from a dictionary."""
def setUp(self):
- self.logger = l = logging.getLogger()
- self.adapter = LoggerAdapter(l, {})
+ self.logger = temp_logger = logging.getLogger()
+ self.adapter = LoggerAdapter(temp_logger, {})
logger_dict = logging.getLogger().manager.loggerDict
logging._acquireLock()
@@ -55,7 +61,6 @@ def setUp(self):
self.root_logger = logging.getLogger("")
self.original_logging_level = self.root_logger.getEffectiveLevel()
-
def tearDown(self):
self.root_logger.setLevel(self.original_logging_level)
logging._acquireLock()
@@ -89,429 +94,287 @@ def next_message(self):
config0 = {
'version': 1,
'formatters': {
- 'form1' : {
- 'format' : '%(levelname)s ++ %(message)s',
- },
- },
- 'handlers' : {
- 'hand1' : {
- '()': testHandler,
- 'formatter': 'form1',
- }
- },
- 'root' : {
- 'level' : 'WARNING',
- 'handlers' : ['hand1'],
- },
- }
+ 'form1': {
+ 'format': '%(levelname)s ++ %(message)s', }, },
+ 'handlers': {'hand1': {
+ '()': testHandler,
+ 'formatter': 'form1', }},
+ 'root': {
+ 'level': 'WARNING',
+ 'handlers': ['hand1'], }, }
# config1 adds a little to the standard configuration.
config1 = {
'version': 1,
'formatters': {
- 'form1' : {
- 'format' : '%(levelname)s ++ %(message)s',
- },
- },
- 'handlers' : {
- 'hand1' : {
- '()': testHandler,
- 'formatter': 'form1',
- }
- },
- 'loggers' : {
- 'compiler.parser' : {
- 'level' : 'DEBUG',
- 'handlers' : ['hand1'],
- },
- },
- 'root' : {
- 'level' : 'WARNING',
- },
- }
+ 'form1': {
+ 'format': '%(levelname)s ++ %(message)s', }, },
+ 'handlers': {'hand1': {
+ '()': testHandler,
+ 'formatter': 'form1', }},
+ 'loggers': {
+ 'compiler.parser': {
+ 'level': 'DEBUG',
+ 'handlers': ['hand1'], }, },
+ 'root': {
+ 'level': 'WARNING', }, }
# config2 has a subtle configuration error that should be reported
config2 = {
'formatters': {
- 'form1' : {
- 'format' : '%(levelname)s ++ %(message)s',
- },
- },
- 'handlers' : {
- 'hand1' : {
- 'class' : 'logging.StreamHandler',
- 'formatter' : 'form1',
- 'level' : 'NOTSET',
- 'stream' : 'ext://sys.stdbout',
- },
- },
- 'loggers' : {
- 'compiler.parser' : {
- 'level' : 'DEBUG',
- 'handlers' : ['hand1'],
- },
- },
- 'root' : {
- 'level' : 'WARNING',
- },
- }
-
- #As config1 but with a misspelt level on a handler
+ 'form1': {
+ 'format': '%(levelname)s ++ %(message)s', }, },
+ 'handlers': {
+ 'hand1': {
+ 'class': 'logging.StreamHandler',
+ 'formatter': 'form1',
+ 'level': 'NOTSET',
+ 'stream': 'ext://sys.stdbout', }, },
+ 'loggers': {
+ 'compiler.parser': {
+ 'level': 'DEBUG',
+ 'handlers': ['hand1'], }, },
+ 'root': {
+ 'level': 'WARNING', }, }
+
+ # As config1 but with a misspelt level on a handler
config2a = {
'formatters': {
- 'form1' : {
- 'format' : '%(levelname)s ++ %(message)s',
- },
- },
- 'handlers' : {
- 'hand1' : {
- 'class' : 'logging.StreamHandler',
- 'formatter' : 'form1',
- 'level' : 'NTOSET',
- 'stream' : 'ext://sys.stdout',
- },
- },
- 'loggers' : {
- 'compiler.parser' : {
- 'level' : 'DEBUG',
- 'handlers' : ['hand1'],
- },
- },
- 'root' : {
- 'level' : 'WARNING',
- },
- }
-
-
- #As config1 but with a misspelt level on a logger
+ 'form1': {
+ 'format': '%(levelname)s ++ %(message)s', }, },
+ 'handlers': {
+ 'hand1': {
+ 'class': 'logging.StreamHandler',
+ 'formatter': 'form1',
+ 'level': 'NTOSET',
+ 'stream': 'ext://sys.stdout', }, },
+ 'loggers': {
+ 'compiler.parser': {
+ 'level': 'DEBUG',
+ 'handlers': ['hand1'], }, },
+ 'root': {
+ 'level': 'WARNING', }, }
+
+ # As config1 but with a misspelt level on a logger
config2b = {
'formatters': {
- 'form1' : {
- 'format' : '%(levelname)s ++ %(message)s',
- },
- },
- 'handlers' : {
- 'hand1' : {
- 'class' : 'logging.StreamHandler',
- 'formatter' : 'form1',
- 'level' : 'NOTSET',
- 'stream' : 'ext://sys.stdout',
- },
- },
- 'loggers' : {
- 'compiler.parser' : {
- 'level' : 'DEBUG',
- 'handlers' : ['hand1'],
- },
- },
- 'root' : {
- 'level' : 'WRANING',
- },
- }
+ 'form1': {
+ 'format': '%(levelname)s ++ %(message)s', }, },
+ 'handlers': {
+ 'hand1': {
+ 'class': 'logging.StreamHandler',
+ 'formatter': 'form1',
+ 'level': 'NOTSET',
+ 'stream': 'ext://sys.stdout', }, },
+ 'loggers': {
+ 'compiler.parser': {
+ 'level': 'DEBUG',
+ 'handlers': ['hand1'], }, },
+ 'root': {
+ 'level': 'WRANING', }, }
# config3 has a less subtle configuration error
config3 = {
'formatters': {
- 'form1' : {
- 'format' : '%(levelname)s ++ %(message)s',
- },
- },
- 'handlers' : {
- 'hand1' : {
- 'class' : 'logging.StreamHandler',
- 'formatter' : 'misspelled_name',
- 'level' : 'NOTSET',
- 'stream' : 'ext://sys.stdout',
- },
- },
- 'loggers' : {
- 'compiler.parser' : {
- 'level' : 'DEBUG',
- 'handlers' : ['hand1'],
- },
- },
- 'root' : {
- 'level' : 'WARNING',
- },
- }
+ 'form1': {
+ 'format': '%(levelname)s ++ %(message)s', }, },
+ 'handlers': {
+ 'hand1': {
+ 'class': 'logging.StreamHandler',
+ 'formatter': 'misspelled_name',
+ 'level': 'NOTSET',
+ 'stream': 'ext://sys.stdout', }, },
+ 'loggers': {
+ 'compiler.parser': {
+ 'level': 'DEBUG',
+ 'handlers': ['hand1'], }, },
+ 'root': {
+ 'level': 'WARNING', }, }
# config4 specifies a custom formatter class to be loaded
config4 = {
'version': 1,
'formatters': {
- 'form1' : {
- '()' : __name__ + '.ExceptionFormatter',
- 'format' : '%(levelname)s:%(name)s:%(message)s',
- },
- },
- 'handlers' : {
- 'hand1' : {
- '()': testHandler,
- 'formatter': 'form1',
- }
- },
- 'root' : {
- 'level' : 'NOTSET',
- 'handlers' : ['hand1'],
- },
- }
+ 'form1': {
+ '()': __name__ + '.ExceptionFormatter',
+ 'format': '%(levelname)s:%(name)s:%(message)s', }, },
+ 'handlers': {'hand1': {
+ '()': testHandler,
+ 'formatter': 'form1', }},
+ 'root': {
+ 'level': 'NOTSET',
+ 'handlers': ['hand1'], }, }
# As config4 but using an actual callable rather than a string
config4a = {
'version': 1,
'formatters': {
- 'form1' : {
- '()' : ExceptionFormatter,
- 'format' : '%(levelname)s:%(name)s:%(message)s',
- },
- 'form2' : {
- '()' : __name__ + '.formatFunc',
- 'format' : '%(levelname)s:%(name)s:%(message)s',
- },
- 'form3' : {
- '()' : formatFunc,
- 'format' : '%(levelname)s:%(name)s:%(message)s',
- },
- },
- 'handlers' : {
- 'hand1' : {
+ 'form1': {
+ '()': ExceptionFormatter,
+ 'format': '%(levelname)s:%(name)s:%(message)s', },
+ 'form2': {
+ '()': __name__ + '.formatFunc',
+ 'format': '%(levelname)s:%(name)s:%(message)s', },
+ 'form3': {
+ '()': formatFunc,
+ 'format': '%(levelname)s:%(name)s:%(message)s', }, },
+ 'handlers': {
+ 'hand1': {
'()': testHandler,
- 'formatter': 'form1',
- },
- 'hand2' : {
- '()' : handlerFunc,
- },
- },
- 'root' : {
- 'level' : 'NOTSET',
- 'handlers' : ['hand1'],
- },
- }
+ 'formatter': 'form1', },
+ 'hand2': {
+ '()': handlerFunc, }, },
+ 'root': {
+ 'level': 'NOTSET',
+ 'handlers': ['hand1'], }, }
# config5 specifies a custom handler class to be loaded
config5 = {
'version': 1,
'formatters': {
- 'form1' : {
- 'format' : '%(levelname)s ++ %(message)s',
- },
- },
- 'handlers' : {
- 'hand1' : {
- '()': testHandler,
- 'formatter': 'form1',
- }
- },
- 'loggers' : {
- 'compiler.parser' : {
- 'level' : 'DEBUG',
- 'handlers' : ['hand1'],
- },
- },
- 'root' : {
- 'level' : 'WARNING',
- },
- }
+ 'form1': {
+ 'format': '%(levelname)s ++ %(message)s', }, },
+ 'handlers': {'hand1': {
+ '()': testHandler,
+ 'formatter': 'form1', }},
+ 'loggers': {
+ 'compiler.parser': {
+ 'level': 'DEBUG',
+ 'handlers': ['hand1'], }, },
+ 'root': {
+ 'level': 'WARNING', }, }
# config6 specifies a custom handler class to be loaded
# but has bad arguments
config6 = {
'formatters': {
- 'form1' : {
- 'format' : '%(levelname)s ++ %(message)s',
- },
- },
- 'handlers' : {
- 'hand1' : {
- 'class' : __name__ + '.CustomHandler',
- 'formatter' : 'form1',
- 'level' : 'NOTSET',
- 'stream' : 'ext://sys.stdout',
- '9' : 'invalid parameter name',
- },
- },
- 'loggers' : {
- 'compiler.parser' : {
- 'level' : 'DEBUG',
- 'handlers' : ['hand1'],
- },
- },
- 'root' : {
- 'level' : 'WARNING',
- },
- }
-
- #config 7 does not define compiler.parser but defines compiler.lexer
- #so compiler.parser should be disabled after applying it
+ 'form1': {
+ 'format': '%(levelname)s ++ %(message)s', }, },
+ 'handlers': {
+ 'hand1': {
+ 'class': __name__ + '.CustomHandler',
+ 'formatter': 'form1',
+ 'level': 'NOTSET',
+ 'stream': 'ext://sys.stdout',
+ '9': 'invalid parameter name', }, },
+ 'loggers': {
+ 'compiler.parser': {
+ 'level': 'DEBUG',
+ 'handlers': ['hand1'], }, },
+ 'root': {
+ 'level': 'WARNING', }, }
+
+ # config 7 does not define compiler.parser but defines compiler.lexer
+ # so compiler.parser should be disabled after applying it
config7 = {
'version': 1,
'formatters': {
- 'form1' : {
- 'format' : '%(levelname)s ++ %(message)s',
- },
- },
- 'handlers' : {
- 'hand1' : {
- '()': testHandler,
- 'formatter': 'form1',
- }
- },
- 'loggers' : {
- 'compiler.lexer' : {
- 'level' : 'DEBUG',
- 'handlers' : ['hand1'],
- },
- },
- 'root' : {
- 'level' : 'WARNING',
- },
- }
+ 'form1': {
+ 'format': '%(levelname)s ++ %(message)s', }, },
+ 'handlers': {'hand1': {
+ '()': testHandler,
+ 'formatter': 'form1', }},
+ 'loggers': {
+ 'compiler.lexer': {
+ 'level': 'DEBUG',
+ 'handlers': ['hand1'], }, },
+ 'root': {
+ 'level': 'WARNING', }, }
config8 = {
'version': 1,
- 'disable_existing_loggers' : False,
+ 'disable_existing_loggers': False,
'formatters': {
- 'form1' : {
- 'format' : '%(levelname)s ++ %(message)s',
- },
- },
- 'handlers' : {
- 'hand1' : {
- '()': testHandler,
- 'formatter': 'form1',
- }
- },
- 'loggers' : {
- 'compiler' : {
- 'level' : 'DEBUG',
- 'handlers' : ['hand1'],
- },
- 'compiler.lexer' : {
- },
- },
- 'root' : {
- 'level' : 'WARNING',
- },
- }
+ 'form1': {
+ 'format': '%(levelname)s ++ %(message)s', }, },
+ 'handlers': {'hand1': {
+ '()': testHandler,
+ 'formatter': 'form1', }},
+ 'loggers': {
+ 'compiler': {
+ 'level': 'DEBUG',
+ 'handlers': ['hand1'], },
+ 'compiler.lexer': {}, },
+ 'root': {
+ 'level': 'WARNING', }, }
config9 = {
'version': 1,
'formatters': {
- 'form1' : {
- 'format' : '%(levelname)s ++ %(message)s',
- },
- },
- 'handlers' : {
- 'hand1' : {
- '()': testHandler,
- 'formatter': 'form1',
- }
- },
- 'loggers' : {
- 'compiler.parser' : {
- 'level' : 'WARNING',
- 'handlers' : ['hand1'],
- },
- },
- 'root' : {
- 'level' : 'NOTSET',
- },
- }
+ 'form1': {
+ 'format': '%(levelname)s ++ %(message)s', }, },
+ 'handlers': {'hand1': {
+ '()': testHandler,
+ 'formatter': 'form1', }},
+ 'loggers': {
+ 'compiler.parser': {
+ 'level': 'WARNING',
+ 'handlers': ['hand1'], }, },
+ 'root': {
+ 'level': 'NOTSET', }, }
config9a = {
'version': 1,
- 'incremental' : True,
- 'handlers' : {
- 'hand1' : {
- 'level' : 'WARNING',
- },
- },
- 'loggers' : {
- 'compiler.parser' : {
- 'level' : 'INFO',
- },
- },
- }
+ 'incremental': True,
+ 'handlers': {
+ 'hand1': {
+ 'level': 'WARNING', }, },
+ 'loggers': {
+ 'compiler.parser': {
+ 'level': 'INFO', }, }, }
config9b = {
'version': 1,
- 'incremental' : True,
- 'handlers' : {
- 'hand1' : {
- 'level' : 'INFO',
- },
- },
- 'loggers' : {
- 'compiler.parser' : {
- 'level' : 'INFO',
- },
- },
- }
-
- #As config1 but with a filter added
+ 'incremental': True,
+ 'handlers': {
+ 'hand1': {
+ 'level': 'INFO', }, },
+ 'loggers': {
+ 'compiler.parser': {
+ 'level': 'INFO', }, }, }
+
+ # As config1 but with a filter added
config10 = {
'version': 1,
'formatters': {
- 'form1' : {
- 'format' : '%(levelname)s ++ %(message)s',
- },
- },
- 'filters' : {
- 'filt1' : {
- 'name' : 'compiler.parser',
- },
- },
- 'handlers' : {
- 'hand1' : {
- '()': testHandler,
- 'formatter': 'form1',
- 'filters' : ['filt1'],
- }
- },
- 'loggers' : {
- 'compiler.parser' : {
- 'level' : 'DEBUG',
- 'filters' : ['filt1'],
- },
- },
- 'root' : {
- 'level' : 'WARNING',
- 'handlers' : ['hand1'],
- },
- }
+ 'form1': {
+ 'format': '%(levelname)s ++ %(message)s', }, },
+ 'filters': {
+ 'filt1': {
+ 'name': 'compiler.parser', }, },
+ 'handlers': {'hand1': {
+ '()': testHandler,
+ 'formatter': 'form1',
+ 'filters': ['filt1'], }},
+ 'loggers': {
+ 'compiler.parser': {
+ 'level': 'DEBUG',
+ 'filters': ['filt1'], }, },
+ 'root': {
+ 'level': 'WARNING',
+ 'handlers': ['hand1'], }, }
# As config10, but declaring a handler in a module using
# absolute imports
config11 = {
'version': 1,
'formatters': {
- 'form1' : {
- 'format' : '%(levelname)s ++ %(message)s',
- },
- },
- 'filters' : {
- 'filt1' : {
- 'name' : 'compiler.parser',
- },
- },
- 'handlers' : {
- 'hand1' : {
- '()': 'mytest.MyTestHandler',
- 'formatter': 'form1',
- 'filters' : ['filt1'],
- }
- },
- 'loggers' : {
- 'compiler.parser' : {
- 'level' : 'DEBUG',
- 'filters' : ['filt1'],
- },
- },
- 'root' : {
- 'level' : 'WARNING',
- 'handlers' : ['hand1'],
- },
- }
+ 'form1': {
+ 'format': '%(levelname)s ++ %(message)s', }, },
+ 'filters': {
+ 'filt1': {
+ 'name': 'compiler.parser', }, },
+ 'handlers': {'hand1': {
+ '()': 'mytest.MyTestHandler',
+ 'formatter': 'form1',
+ 'filters': ['filt1'], }},
+ 'loggers': {
+ 'compiler.parser': {
+ 'level': 'DEBUG',
+ 'filters': ['filt1'], }, },
+ 'root': {
+ 'level': 'WARNING',
+ 'handlers': ['hand1'], }, }
def apply_config(self, conf):
dictConfig(conf)
@@ -526,9 +389,7 @@ def test_config0_ok(self):
logger.error(self.next_message())
h = logger.handlers[0]
self.assertEqual(1, h.count)
- self.assertTrue(h.matchall([
- dict(levelname='ERROR', message='2')
- ]))
+ self.assertTrue(h.matchall([dict(levelname='ERROR', message='2')]))
def test_config1_ok(self, config=config1):
# A config defining a sub-parser as well.
@@ -539,9 +400,8 @@ def test_config1_ok(self, config=config1):
logger.error(self.next_message())
h = logger.handlers[0]
self.assertTrue(h.matchall([
- dict(levelname='INFO', message='1'),
- dict(levelname='ERROR', message='2'),
- ]))
+ dict(levelname='INFO', message='1'),
+ dict(levelname='ERROR', message='2'), ]))
def test_config2_failure(self):
# A simple config which overrides the default settings.
@@ -568,8 +428,7 @@ def test_config4_ok(self):
raise RuntimeError()
except RuntimeError:
logging.exception("just testing")
- self.assertEquals(h.formatted[0],
- "ERROR:root:just testing\nGot a [RuntimeError]")
+ self.assertEquals(h.formatted[0], "ERROR:root:just testing\nGot a [RuntimeError]")
def test_config4a_ok(self):
# A config specifying a custom formatter class.
@@ -580,8 +439,7 @@ def test_config4a_ok(self):
raise RuntimeError()
except RuntimeError:
logging.exception("just testing")
- self.assertEquals(h.formatted[0],
- "ERROR:root:just testing\nGot a [RuntimeError]")
+ self.assertEquals(h.formatted[0], "ERROR:root:just testing\nGot a [RuntimeError]")
def test_config5_ok(self):
self.test_config1_ok(config=self.config5)
@@ -597,9 +455,8 @@ def test_config7_ok(self):
logger.error(self.next_message())
h = logger.handlers[0]
self.assertTrue(h.matchall([
- dict(levelname='INFO', message='1'),
- dict(levelname='ERROR', message='2'),
- ]))
+ dict(levelname='INFO', message='1'),
+ dict(levelname='ERROR', message='2'), ]))
self.apply_config(self.config7)
logger = logging.getLogger("compiler.parser")
self.assertTrue(logger.disabled)
@@ -609,11 +466,10 @@ def test_config7_ok(self):
logger.info(self.next_message())
logger.error(self.next_message())
self.assertTrue(h.matchall([
- dict(levelname='INFO', message='3'),
- dict(levelname='ERROR', message='4'),
- ]))
+ dict(levelname='INFO', message='3'),
+ dict(levelname='ERROR', message='4'), ]))
- #Same as test_config_7_ok but don't disable old loggers.
+ # Same as test_config_7_ok but don't disable old loggers.
def test_config_8_ok(self):
self.apply_config(self.config1)
logger = logging.getLogger("compiler.parser")
@@ -622,9 +478,8 @@ def test_config_8_ok(self):
logger.error(self.next_message())
h = logger.handlers[0]
self.assertTrue(h.matchall([
- dict(levelname='INFO', message='1'),
- dict(levelname='ERROR', message='2'),
- ]))
+ dict(levelname='INFO', message='1'),
+ dict(levelname='ERROR', message='2'), ]))
self.apply_config(self.config8)
logger = logging.getLogger("compiler.parser")
self.assertFalse(logger.disabled)
@@ -637,22 +492,22 @@ def test_config_8_ok(self):
logger.info(self.next_message())
logger.error(self.next_message())
h = toplogger.handlers[0]
- self.assertTrue(h.matchall([
- dict(levelname='INFO', message='3'),
- dict(levelname='ERROR', message='4'),
- dict(levelname='INFO', message='5'),
- dict(levelname='ERROR', message='6'),
- ]))
+ self.assertTrue(
+ h.matchall([
+ dict(levelname='INFO', message='3'),
+ dict(levelname='ERROR', message='4'),
+ dict(levelname='INFO', message='5'),
+ dict(levelname='ERROR', message='6'), ]))
def test_config_9_ok(self):
self.apply_config(self.config9)
logger = logging.getLogger("compiler.parser")
- #Nothing will be output since both handler and logger are set to WARNING
+ # Nothing will be output since both handler and logger are set to WARNING
logger.info(self.next_message())
h = logger.handlers[0]
self.assertEqual(0, h.count)
self.apply_config(self.config9a)
- #Nothing will be output since both handler is still set to WARNING
+ # Nothing will be output since both handler is still set to WARNING
logger.info(self.next_message())
h = logger.handlers[0]
nhs = named_handlers_supported()
@@ -661,13 +516,12 @@ def test_config_9_ok(self):
else:
self.assertEqual(1, h.count)
self.apply_config(self.config9b)
- #Message should now be output
+ # Message should now be output
logger.info(self.next_message())
if nhs:
h = logger.handlers[0]
self.assertTrue(h.matchall([
- dict(levelname='INFO', message='3'),
- ]))
+ dict(levelname='INFO', message='3'), ]))
else:
self.assertEqual(2, h.count)
@@ -676,19 +530,18 @@ def test_config_10_ok(self):
logger = logging.getLogger("compiler.parser")
logger.warning(self.next_message())
logger = logging.getLogger('compiler')
- #Not output, because filtered
+ # Not output, because filtered
logger.warning(self.next_message())
logger = logging.getLogger('compiler.lexer')
- #Not output, because filtered
+ # Not output, because filtered
logger.warning(self.next_message())
logger = logging.getLogger("compiler.parser.codegen")
- #Output, as not filtered
+ # Output, as not filtered
logger.error(self.next_message())
h = logging.getLogger().handlers[0]
self.assertTrue(h.matchall([
- dict(levelname='WARNING', message='1'),
- dict(levelname='ERROR', message='4'),
- ]))
+ dict(levelname='WARNING', message='1'),
+ dict(levelname='ERROR', message='4'), ]))
def test_config_11_ok(self):
self.apply_config(self.config11)
diff --git a/splunk_eventgen/lib/logutils_src/tests/test_formatter.py b/splunk_eventgen/lib/logutils_src/tests/test_formatter.py
index 0a069c78..011ba234 100644
--- a/splunk_eventgen/lib/logutils_src/tests/test_formatter.py
+++ b/splunk_eventgen/lib/logutils_src/tests/test_formatter.py
@@ -2,11 +2,13 @@
# Copyright (C) 2009-2017 Vinay Sajip. See LICENSE.txt for details.
#
import logging
-import logutils
import os
import sys
import unittest
+import logutils
+
+
class FormatterTest(unittest.TestCase):
def setUp(self):
self.common = {
@@ -17,10 +19,8 @@ def setUp(self):
'exc_info': None,
'func': None,
'msg': 'Message with %d %s',
- 'args': (2, 'placeholders'),
- }
- self.variants = {
- }
+ 'args': (2, 'placeholders'), }
+ self.variants = {}
def get_record(self, name=None):
result = dict(self.common)
@@ -42,6 +42,7 @@ def test_percent(self):
self.assertFalse(f.usesTime())
if sys.version_info[:2] >= (2, 6):
+
def test_braces(self):
"Test {}-formatting"
r = self.get_record()
diff --git a/splunk_eventgen/lib/logutils_src/tests/test_messages.py b/splunk_eventgen/lib/logutils_src/tests/test_messages.py
index 17f80bbd..0a221105 100644
--- a/splunk_eventgen/lib/logutils_src/tests/test_messages.py
+++ b/splunk_eventgen/lib/logutils_src/tests/test_messages.py
@@ -1,9 +1,12 @@
-import logutils
import sys
import unittest
+import logutils
+
+
class MessageTest(unittest.TestCase):
if sys.version_info[:2] >= (2, 6):
+
def test_braces(self):
"Test whether brace-formatting works."
__ = logutils.BraceMessage
@@ -19,8 +22,7 @@ class Dummy:
dummy = Dummy()
dummy.x, dummy.y = 0.0, 1.0
- m = __('Message with coordinates: ({point.x:.2f}, {point.y:.2f})',
- point=dummy)
+ m = __('Message with coordinates: ({point.x:.2f}, {point.y:.2f})', point=dummy)
self.assertEqual(str(m), 'Message with coordinates: (0.00, 1.00)')
def test_dollars(self):
@@ -29,5 +31,4 @@ def test_dollars(self):
m = __('Message with $num ${what}', num=2, what='placeholders')
self.assertEqual(str(m), 'Message with 2 placeholders')
ignored = object()
- self.assertRaises(TypeError, __, 'Message with $num ${what}',
- ignored, num=2, what='placeholders')
+ self.assertRaises(TypeError, __, 'Message with $num ${what}', ignored, num=2, what='placeholders')
diff --git a/splunk_eventgen/lib/logutils_src/tests/test_queue.py b/splunk_eventgen/lib/logutils_src/tests/test_queue.py
index 34152e37..f85074c6 100644
--- a/splunk_eventgen/lib/logutils_src/tests/test_queue.py
+++ b/splunk_eventgen/lib/logutils_src/tests/test_queue.py
@@ -2,19 +2,21 @@
# Copyright (C) 2010-2017 Vinay Sajip. See LICENSE.txt for details.
#
import logging
-from logutils.testing import TestHandler, Matcher
-from logutils.queue import QueueHandler, QueueListener, queue
import unittest
+from logutils.queue import QueueHandler, QueueListener, queue
+from logutils.testing import Matcher, TestHandler
+
+
class QueueTest(unittest.TestCase):
def setUp(self):
self.handler = h = TestHandler(Matcher())
- self.logger = l = logging.getLogger()
+ self.logger = temp_logger = logging.getLogger()
self.queue = q = queue.Queue(-1)
self.qh = qh = QueueHandler(q)
self.ql = ql = QueueListener(q, h)
ql.start()
- l.addHandler(qh)
+ temp_logger.addHandler(qh)
def tearDown(self):
self.logger.removeHandler(self.qh)
@@ -28,9 +30,8 @@ def test_simple(self):
self.logger.debug("This won't show up.")
self.logger.info("Neither will this.")
self.logger.warning("But this will.")
- self.ql.stop() #ensure all records have come through.
+ self.ql.stop() # ensure all records have come through.
h = self.handler
- #import pdb; pdb.set_trace()
self.assertTrue(h.matches(levelno=logging.WARNING))
self.assertFalse(h.matches(levelno=logging.DEBUG))
self.assertFalse(h.matches(levelno=logging.INFO))
@@ -42,10 +43,10 @@ def test_partial(self):
self.logger.debug("This won't show up.")
self.logger.info("Neither will this.")
self.logger.warning("But this will.")
- self.ql.stop() #ensure all records have come through.
+ self.ql.stop() # ensure all records have come through.
h = self.handler
- self.assertTrue(h.matches(msg="ut th")) # from "But this will"
- self.assertTrue(h.matches(message="ut th")) # from "But this will"
+ self.assertTrue(h.matches(msg="ut th")) # from "But this will"
+ self.assertTrue(h.matches(message="ut th")) # from "But this will"
self.assertFalse(h.matches(message="either"))
self.assertFalse(h.matches(message="won't"))
@@ -57,13 +58,12 @@ def test_multiple(self):
self.logger.info("Neither will this.")
self.logger.warning("But this will.")
self.logger.error("And so will this.")
- self.ql.stop() #ensure all records have come through.
+ self.ql.stop() # ensure all records have come through.
h = self.handler
- self.assertTrue(h.matches(levelno=logging.WARNING,
- message='ut thi'))
- self.assertTrue(h.matches(levelno=logging.ERROR,
- message='nd so wi'))
+ self.assertTrue(h.matches(levelno=logging.WARNING, message='ut thi'))
+ self.assertTrue(h.matches(levelno=logging.ERROR, message='nd so wi'))
self.assertFalse(h.matches(levelno=logging.INFO))
+
if __name__ == '__main__':
unittest.main()
diff --git a/splunk_eventgen/lib/logutils_src/tests/test_redis.py b/splunk_eventgen/lib/logutils_src/tests/test_redis.py
index 858192cd..e53bdb5d 100644
--- a/splunk_eventgen/lib/logutils_src/tests/test_redis.py
+++ b/splunk_eventgen/lib/logutils_src/tests/test_redis.py
@@ -2,14 +2,17 @@
# Copyright (C) 2011-2017 Vinay Sajip. See LICENSE.txt for details.
#
import logging
-from logutils.testing import TestHandler, Matcher
-from logutils.redis import RedisQueueHandler, RedisQueueListener
-from redis import Redis
import socket
import subprocess
import time
import unittest
+from logutils.redis import RedisQueueHandler, RedisQueueListener
+from logutils.testing import Matcher, TestHandler
+
+from redis import Redis
+
+
class QueueListener(RedisQueueListener):
def dequeue(self, block):
record = RedisQueueListener.dequeue(self, block)
@@ -17,19 +20,18 @@ def dequeue(self, block):
record = logging.makeLogRecord(record)
return record
+
class RedisQueueTest(unittest.TestCase):
def setUp(self):
self.handler = h = TestHandler(Matcher())
- self.logger = l = logging.getLogger()
- self.server = subprocess.Popen(['redis-server'],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ self.logger = temp_logger = logging.getLogger()
+ self.server = subprocess.Popen(['redis-server'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
self.wait_for_server()
self.queue = q = Redis()
self.qh = qh = RedisQueueHandler(redis=q)
self.ql = ql = QueueListener(h, redis=q)
ql.start()
- l.addHandler(qh)
+ temp_logger.addHandler(qh)
def tearDown(self):
self.logger.removeHandler(self.qh)
@@ -38,7 +40,7 @@ def tearDown(self):
self.server.terminate()
def wait_for_server(self):
- maxtime = time.time() + 2 # 2 seconds to wait for server
+ maxtime = time.time() + 2 # 2 seconds to wait for server
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while time.time() < maxtime:
try:
@@ -57,9 +59,8 @@ def test_simple(self):
self.logger.debug("This won't show up.")
self.logger.info("Neither will this.")
self.logger.warning("But this will.")
- self.ql.stop() #ensure all records have come through.
+ self.ql.stop() # ensure all records have come through.
h = self.handler
- #import pdb; pdb.set_trace()
self.assertTrue(h.matches(levelno=logging.WARNING))
self.assertFalse(h.matches(levelno=logging.DEBUG))
self.assertFalse(h.matches(levelno=logging.INFO))
@@ -71,10 +72,10 @@ def test_partial(self):
self.logger.debug("This won't show up.")
self.logger.info("Neither will this.")
self.logger.warning("But this will.")
- self.ql.stop() #ensure all records have come through.
+ self.ql.stop() # ensure all records have come through.
h = self.handler
- self.assertTrue(h.matches(msg="ut th")) # from "But this will"
- self.assertTrue(h.matches(message="ut th")) # from "But this will"
+ self.assertTrue(h.matches(msg="ut th")) # from "But this will"
+ self.assertTrue(h.matches(message="ut th")) # from "But this will"
self.assertFalse(h.matches(message="either"))
self.assertFalse(h.matches(message="won't"))
@@ -86,13 +87,12 @@ def test_multiple(self):
self.logger.info("Neither will this.")
self.logger.warning("But this will.")
self.logger.error("And so will this.")
- self.ql.stop() #ensure all records have come through.
+ self.ql.stop() # ensure all records have come through.
h = self.handler
- self.assertTrue(h.matches(levelno=logging.WARNING,
- message='ut thi'))
- self.assertTrue(h.matches(levelno=logging.ERROR,
- message='nd so wi'))
+ self.assertTrue(h.matches(levelno=logging.WARNING, message='ut thi'))
+ self.assertTrue(h.matches(levelno=logging.ERROR, message='nd so wi'))
self.assertFalse(h.matches(levelno=logging.INFO))
+
if __name__ == '__main__':
unittest.main()
diff --git a/splunk_eventgen/lib/logutils_src/tests/test_testing.py b/splunk_eventgen/lib/logutils_src/tests/test_testing.py
index c0b7409a..ef61beb7 100644
--- a/splunk_eventgen/lib/logutils_src/tests/test_testing.py
+++ b/splunk_eventgen/lib/logutils_src/tests/test_testing.py
@@ -2,21 +2,23 @@
# Copyright (C) 2010-2017 Vinay Sajip. See LICENSE.txt for details.
#
import logging
-from logutils.testing import TestHandler, Matcher
import unittest
+from logutils.testing import Matcher, TestHandler
+
+
class LoggingTest(unittest.TestCase):
def setUp(self):
self.handler = h = TestHandler(Matcher())
- self.logger = l = logging.getLogger()
- l.addHandler(h)
+ self.logger = temp_logger = logging.getLogger()
+ temp_logger.addHandler(h)
def tearDown(self):
self.logger.removeHandler(self.handler)
self.handler.close()
def test_simple(self):
- "Simple test of logging test harness."
+ """Simple test of logging test harness."""
# Just as a demo, let's log some messages.
# Only one should show up in the log.
self.logger.debug("This won't show up.")
@@ -28,20 +30,20 @@ def test_simple(self):
self.assertFalse(h.matches(levelno=logging.INFO))
def test_partial(self):
- "Test of partial matching in logging test harness."
+ """Test of partial matching in logging test harness."""
# Just as a demo, let's log some messages.
# Only one should show up in the log.
self.logger.debug("This won't show up.")
self.logger.info("Neither will this.")
self.logger.warning("But this will.")
h = self.handler
- self.assertTrue(h.matches(msg="ut th")) # from "But this will"
- self.assertTrue(h.matches(message="ut th")) # from "But this will"
+ self.assertTrue(h.matches(msg="ut th")) # from "But this will"
+ self.assertTrue(h.matches(message="ut th")) # from "But this will"
self.assertFalse(h.matches(message="either"))
self.assertFalse(h.matches(message="won't"))
def test_multiple(self):
- "Test of matching multiple values in logging test harness."
+ """Test of matching multiple values in logging test harness."""
# Just as a demo, let's log some messages.
# Only one should show up in the log.
self.logger.debug("This won't show up.")
@@ -49,11 +51,10 @@ def test_multiple(self):
self.logger.warning("But this will.")
self.logger.error("And so will this.")
h = self.handler
- self.assertTrue(h.matches(levelno=logging.WARNING,
- message='ut thi'))
- self.assertTrue(h.matches(levelno=logging.ERROR,
- message='nd so wi'))
+ self.assertTrue(h.matches(levelno=logging.WARNING, message='ut thi'))
+ self.assertTrue(h.matches(levelno=logging.ERROR, message='nd so wi'))
self.assertFalse(h.matches(levelno=logging.INFO))
+
if __name__ == '__main__':
unittest.main()
diff --git a/splunk_eventgen/lib/outputcounter.py b/splunk_eventgen/lib/outputcounter.py
index 37547f11..46d455e2 100644
--- a/splunk_eventgen/lib/outputcounter.py
+++ b/splunk_eventgen/lib/outputcounter.py
@@ -1,11 +1,13 @@
-import time
import logging
+import time
+
class OutputCounter(object):
'''
This object is used as a global variable for outputer to collect how many events and how much size of
raw events egx has generated, and use them to calculate a real-time throughput.
'''
+
def __init__(self):
self.event_size_1_min = 0
self.event_count_1_min = 0
@@ -24,7 +26,8 @@ def update_throughput(self, timestamp):
self.current_time = timestamp
self.event_count_1_min = 0
self.event_size_1_min = 0
- self.logger.error("Current throughput is {} B/s, {} count/s".format(self.throughput_volume, self.throughput_count))
+ self.logger.debug("Current throughput is {} B/s, {} count/s".format(self.throughput_volume,
+ self.throughput_count))
def collect(self, event_count, event_size):
timestamp = time.time()
diff --git a/splunk_eventgen/lib/outputplugin.py b/splunk_eventgen/lib/outputplugin.py
index f1dee615..e3bb2fb3 100644
--- a/splunk_eventgen/lib/outputplugin.py
+++ b/splunk_eventgen/lib/outputplugin.py
@@ -1,8 +1,10 @@
from __future__ import division
+
import logging
import logging.handlers
from collections import deque
+
class OutputPlugin(object):
name = 'OutputPlugin'
@@ -12,14 +14,15 @@ def __init__(self, sample, output_counter=None):
self._outputMode = sample.outputMode
self.events = None
self._setup_logging()
- self.logger.debug("Starting OutputPlugin for sample '%s' with output '%s'" % (self._sample.name, self._sample.outputMode))
+ self.logger.debug(
+ "Starting OutputPlugin for sample '%s' with output '%s'" % (self._sample.name, self._sample.outputMode))
self._queue = deque([])
self.output_counter = output_counter
def __str__(self):
"""Only used for debugging, outputs a pretty printed representation of this output"""
# Eliminate recursive going back to parent
- temp = dict([ (key, value) for (key, value) in self.__dict__.items() if key != '_c'])
+ # temp = dict([(key, value) for (key, value) in self.__dict__.items() if key != '_c'])
# return pprint.pformat(temp)
return ""
@@ -55,4 +58,4 @@ def run(self):
def load():
- return OutputPlugin
\ No newline at end of file
+ return OutputPlugin
diff --git a/splunk_eventgen/lib/plugins/generator/default.py b/splunk_eventgen/lib/plugins/generator/default.py
index 52bafe19..ed106e39 100644
--- a/splunk_eventgen/lib/plugins/generator/default.py
+++ b/splunk_eventgen/lib/plugins/generator/default.py
@@ -1,11 +1,12 @@
-# TODO Sample object now incredibly overloaded and not threadsafe. Need to make it threadsafe and make it simpler to get a
-# copy of whats needed without the whole object.
+# TODO: Sample object is incredibly overloaded and not threadsafe. Need to make it simpler to get a copy without the
+# whole object get a copy of whats needed without the whole object.
from __future__ import division
-from generatorplugin import GeneratorPlugin
-import datetime, time
+
+import datetime
import random
-from eventgentimestamp import EventgenTimestamp
+
+from generatorplugin import GeneratorPlugin
class DefaultGenerator(GeneratorPlugin):
@@ -13,27 +14,29 @@ def __init__(self, sample):
GeneratorPlugin.__init__(self, sample)
def gen(self, count, earliest, latest, samplename=None):
- s = self._sample
-
- self.logger.debug("Generating sample '%s' in app '%s' with count %d, et: '%s', lt '%s'" % (self._sample.name, self._sample.app, count, earliest, latest))
+ self.logger.debug("Generating sample '%s' in app '%s' with count %d, et: '%s', lt '%s'" %
+ (self._sample.name, self._sample.app, count, earliest, latest))
startTime = datetime.datetime.now()
# If we're random, fill random events from sampleDict into eventsDict
if self._sample.randomizeEvents:
- eventsDict = [ ]
+ eventsDict = []
sdlen = len(self._sample.sampleDict)
- self.logger.debugv("Random filling eventsDict for sample '%s' in app '%s' with %d events" % (self._sample.name, self._sample.app, count))
- # Count is -1, replay the whole file, but in randomizeEvents I think we'd want it to actually
+ self.logger.debugv("Random filling eventsDict for sample '%s' in app '%s' with %d events" %
+ (self._sample.name, self._sample.app, count))
+ # Count is -1, replay the whole file, but in randomizeEvents I think we'd want it to actually
# just put as many events as there are in the file
if count == -1:
count = sdlen
while len(eventsDict) < count:
- eventsDict.append(self._sample.sampleDict[random.randint(0, sdlen-1)])
+ eventsDict.append(self._sample.sampleDict[random.randint(0, sdlen - 1)])
# If we're bundlelines, create count copies of the sampleDict
elif self._sample.bundlelines:
- eventsDict = [ ]
- self.logger.debugv("Bundlelines, filling eventsDict for sample '%s' in app '%s' with %d copies of sampleDict" % (self._sample.name, self._sample.app, count))
+ eventsDict = []
+ self.logger.debugv(
+ "Bundlelines, filling eventsDict for sample '%s' in app '%s' with %d copies of sampleDict" %
+ (self._sample.name, self._sample.app, count))
for x in xrange(count):
eventsDict.extend(self._sample.sampleDict)
@@ -45,9 +48,11 @@ def gen(self, count, earliest, latest, samplename=None):
count = len(self._sample.sampleDict)
eventsDict = self._sample.sampleDict[0:count]
- ## Continue to fill events array until len(events) == count
+ # Continue to fill events array until len(events) == count
if len(eventsDict) < count:
- self.logger.debugv("Events fill for sample '%s' in app '%s' less than count (%s vs. %s); continuing fill" % (self._sample.name, self._sample.app, len(eventsDict), count) )
+ self.logger.debugv(
+ "Events fill for sample '%s' in app '%s' less than count (%s vs. %s); continuing fill" %
+ (self._sample.name, self._sample.app, len(eventsDict), count))
self.logger.debugv("Current eventsDict: %s" % eventsDict)
# run a modulus on the size of the eventdict to figure out what the last event was. Populate to count
# from there.
@@ -57,9 +62,11 @@ def gen(self, count, earliest, latest, samplename=None):
nextEventToUse = self._sample.sampleDict[len(eventsDict) % len(self._sample.sampleDict)]
self.logger.debugv("Next event to add: %s" % nextEventToUse)
eventsDict.append(nextEventToUse)
- self.logger.debugv("Events fill complete for sample '%s' in app '%s' length %d" % (self._sample.name, self._sample.app, len(eventsDict)))
+ self.logger.debugv("Events fill complete for sample '%s' in app '%s' length %d" %
+ (self._sample.name, self._sample.app, len(eventsDict)))
GeneratorPlugin.build_events(self, eventsDict, startTime, earliest, latest)
+
def load():
return DefaultGenerator
diff --git a/splunk_eventgen/lib/plugins/generator/jinja.py b/splunk_eventgen/lib/plugins/generator/jinja.py
index 52f3e63c..96af5c6f 100644
--- a/splunk_eventgen/lib/plugins/generator/jinja.py
+++ b/splunk_eventgen/lib/plugins/generator/jinja.py
@@ -1,20 +1,21 @@
from __future__ import division
+
import datetime
-import time
import os
import random
-try:
- import ujson as json
-except:
- import json as json
+import time
+
from jinja2 import nodes
from jinja2.ext import Extension
from generatorplugin import GeneratorPlugin
+try:
+ import ujson as json
+except:
+ import json as json
class CantFindTemplate(Exception):
-
def __init__(self, msg):
"""Exception raised when we / Jinja can't find the template
@@ -23,9 +24,7 @@ def __init__(self, msg):
self.msg = msg
super(CantFindTemplate, self).__init__(msg)
-
class CantProcessTemplate(Exception):
-
def __init__(self, msg):
"""Exception raised when we / Jinja can't find the template
@@ -41,8 +40,8 @@ class JinjaTime(Extension):
@staticmethod
def _get_time_slice(earliest, latest, slices, target_slice, slice_type="lower"):
"""
- This method will take a time block bounded by "earliest and latest", and a slice. It'll then divide the time
- in sections and return a tuple with 3 arguments, the lower bound, the higher bound, and the target in the middle.
+ This method will take a time block bounded by "earliest and latest", and a slice. It'll then divide the time in
+ sections and return a tuple with 3 arguments, the lower bound, the higher bound, and the target in the middle.
:param earliest (in epoch):
:param latest (in epoch):
:param slices:
@@ -62,12 +61,12 @@ def _get_time_slice(earliest, latest, slices, target_slice, slice_type="lower"):
if slice_type == "lower":
slice_time = slice_start
elif slice_type == "middle":
- slice_time = slice_start + (slice_size/2)
+ slice_time = slice_start + (slice_size / 2)
elif slice_type == "upper":
slice_time = slice_end
elif slice_type == "random":
- start = int(slice_start*100)
- end = int(slice_end*100)
+ start = int(slice_start * 100)
+ end = int(slice_end * 100)
if start == end:
slice_time = end * 0.01
else:
@@ -93,7 +92,8 @@ def _time_slice_formatted(self, earliest, latest, count, slices, date_format='%Y
def _time_slice_epoch(self, earliest, latest, count, slices, date_format=None):
slice_start, slice_end, slice_size, slice_time = \
- self._get_time_slice(earliest=earliest, latest=latest, slices=slices, target_slice=count, slice_type="lower")
+ self._get_time_slice(earliest=earliest, latest=latest, slices=slices, target_slice=count,
+ slice_type="lower")
return slice_time
@staticmethod
@@ -106,17 +106,14 @@ def _output_var(var_value, lineno):
return nodes.Output([var_value], lineno=lineno)
def parse(self, parser):
- target_var_name = {
- "time_now": "time_now",
- "time_slice": "time_target"
- }
+ target_var_name = {"time_now": "time_now", "time_slice": "time_target"}
tag = parser.stream.current.value
name_base = target_var_name[tag]
lineno = parser.stream.next().lineno
args, kwargs = self.parse_args(parser)
task_list = []
- epoch_name = name_base+"_epoch"
- formatted_name = name_base+"_formatted"
+ epoch_name = name_base + "_epoch"
+ formatted_name = name_base + "_formatted"
target_epoch_method = "_{0}_epoch".format(tag)
target_formatted_method = "_{0}_formatted".format(tag)
epoch_call = self.call_method(target_epoch_method, args=args, kwargs=kwargs, lineno=lineno)
@@ -139,8 +136,7 @@ def parse_args(self, parser):
kwargs.append(nodes.Keyword(key, value, lineno=value.lineno))
else:
if kwargs:
- parser.fail('Invalid argument syntax for WrapExtension tag',
- parser.stream.current.lineno)
+ parser.fail('Invalid argument syntax for WrapExtension tag', parser.stream.current.lineno)
args.append(parser.parse_expression())
require_comma = True
return args, kwargs
@@ -212,11 +208,10 @@ def gen(self, count, earliest, latest, samplename=None):
if not hasattr(self._sample, "jinja_target_template"):
raise CantFindTemplate("Template to load not specified in eventgen conf for stanza. Skipping Stanza")
jinja_env = Environment(
- loader=FileSystemLoader([target_template_dir, working_dir, template_dir], encoding='utf-8', followlinks=False),
- extensions=['jinja2.ext.do', 'jinja2.ext.with_', 'jinja2.ext.loopcontrols', JinjaTime],
- line_statement_prefix="#",
- line_comment_prefix="##"
- )
+ loader=FileSystemLoader([target_template_dir, working_dir, template_dir], encoding='utf-8',
+ followlinks=False), extensions=[
+ 'jinja2.ext.do', 'jinja2.ext.with_', 'jinja2.ext.loopcontrols', JinjaTime],
+ line_statement_prefix="#", line_comment_prefix="##")
jinja_loaded_template = jinja_env.get_template(str(self._sample.jinja_target_template))
if hasattr(self._sample, 'jinja_variables'):
@@ -227,36 +222,40 @@ def gen(self, count, earliest, latest, samplename=None):
jinja_loaded_vars["eventgen_count"] = self.current_count
jinja_loaded_vars["eventgen_maxcount"] = self.target_count
jinja_loaded_vars["eventgen_earliest"] = self.earliest
- self.earliest_epoch = (self.earliest - datetime.datetime(1970,1,1)).total_seconds()
+ self.earliest_epoch = (self.earliest - datetime.datetime(1970, 1, 1)).total_seconds()
jinja_loaded_vars["eventgen_earliest_epoch"] = self.earliest_epoch
jinja_loaded_vars["eventgen_latest"] = self.latest
- jinja_loaded_vars["eventgen_latest_epoch"] = (self.latest - datetime.datetime(1970,1,1)).total_seconds()
- self.latest_epoch = (self.latest - datetime.datetime(1970,1,1)).total_seconds()
+ jinja_loaded_vars["eventgen_latest_epoch"] = (self.latest - datetime.datetime(1970, 1, 1)).total_seconds()
+ self.latest_epoch = (self.latest - datetime.datetime(1970, 1, 1)).total_seconds()
while self.current_count < self.target_count:
self.end_of_cycle = False
jinja_loaded_vars["eventgen_count"] = self.current_count
jinja_loaded_vars["eventgen_target_time_earliest"], jinja_loaded_vars["eventgen_target_time_latest"], \
- jinja_loaded_vars["eventgen_target_time_slice_size"], jinja_loaded_vars["eventgen_target_time_epoch"] = \
- JinjaTime._get_time_slice(self.earliest_epoch, self.latest_epoch, self.target_count, self.current_count, slice_type="random")
+ jinja_loaded_vars["eventgen_target_time_slice_size"], \
+ jinja_loaded_vars["eventgen_target_time_epoch"] = \
+ JinjaTime._get_time_slice(self.earliest_epoch, self.latest_epoch, self.target_count,
+ self.current_count, slice_type="random")
self.jinja_stream = jinja_loaded_template.stream(jinja_loaded_vars)
lines_out = []
try:
for line in self.jinja_stream:
if line != "\n":
- #TODO: Time can be supported by self._sample.timestamp, should probably set that up in this logic.
+ # TODO: Time can be supported by self._sample.timestamp, should probably set that up here.
try:
target_line = json.loads(line)
except ValueError as e:
self.logger.error("Unable to parse Jinja's return. Line: {0}".format(line))
self.logger.error("Parse Failure Reason: {0}".format(e.message))
- self.logger.error("Please note, you must meet the requirements for json.loads in python if you have not installed ujson. Native python does not support multi-line events.")
+ self.logger.error(
+ "Please note, you must meet the requirements for json.loads in python if you have" +
+ "not installed ujson. Native python does not support multi-line events.")
continue
current_line_keys = target_line.keys()
if "_time" not in current_line_keys:
- #TODO: Add a custom exception here
+ # TODO: Add a custom exception here
raise Exception("No _time field supplied, please add time to your jinja template.")
if "_raw" not in current_line_keys:
- #TODO: Add a custom exception here
+ # TODO: Add a custom exception here
raise Exception("No _raw field supplied, please add time to your jinja template.")
if "host" not in current_line_keys:
target_line["host"] = self._sample.host
@@ -281,7 +280,7 @@ def gen(self, count, earliest, latest, samplename=None):
timeDiffFrac = "%d.%06d" % (timeDiff.seconds, timeDiff.microseconds)
self.logger.debugv("Interval complete, flushing feed")
self._out.flush(endOfInterval=True)
- self.logger.info("Generation of sample '%s' completed in %s seconds." % (self._sample.name, timeDiffFrac) )
+ self.logger.info("Generation of sample '%s' completed in %s seconds." % (self._sample.name, timeDiffFrac))
return 0
except Exception as e:
self.logger.exception(e)
diff --git a/splunk_eventgen/lib/plugins/generator/perdayvolumegenerator.py b/splunk_eventgen/lib/plugins/generator/perdayvolumegenerator.py
index 7e91948c..c58f7bae 100644
--- a/splunk_eventgen/lib/plugins/generator/perdayvolumegenerator.py
+++ b/splunk_eventgen/lib/plugins/generator/perdayvolumegenerator.py
@@ -1,18 +1,21 @@
from __future__ import division
-from generatorplugin import GeneratorPlugin
-import datetime, time
+
+import datetime
import random
+from generatorplugin import GeneratorPlugin
+
class PerDayVolumeGenerator(GeneratorPlugin):
def __init__(self, sample):
GeneratorPlugin.__init__(self, sample)
- #TODO: Make this work with replay mode.
+ # TODO: Make this work with replay mode.
def gen(self, count, earliest, latest, samplename=None):
# count in this plugin is a measurement of byteself._sample.
size = count
- self.logger.debug("PerDayVolumeGenerator Called with a Size of: %s with Earliest: %s and Latest: %s" % (size, earliest, latest))
+ self.logger.debug("PerDayVolumeGenerator Called with a Size of: %s with Earliest: %s and Latest: %s" %
+ (size, earliest, latest))
# very similar to the default generator. only difference is we go by size instead of count.
try:
self._sample.loadSample()
@@ -21,7 +24,8 @@ def gen(self, count, earliest, latest, samplename=None):
self.logger.error("Error loading sample file for sample '%s'" % self._sample.name)
return
- self.logger.debug("Generating sample '%s' in app '%s' with count %d, et: '%s', lt '%s'" % (self._sample.name, self._sample.app, size, earliest, latest))
+ self.logger.debug("Generating sample '%s' in app '%s' with count %d, et: '%s', lt '%s'" %
+ (self._sample.name, self._sample.app, size, earliest, latest))
startTime = datetime.datetime.now()
# Create a counter for the current byte size of the read in samples
@@ -33,15 +37,18 @@ def gen(self, count, earliest, latest, samplename=None):
eventsDict = []
if self._sample.randomizeEvents:
sdlen = len(updated_sample_dict)
- self.logger.debugv("Random filling eventsDict for sample '%s' in app '%s' with %d bytes" % (self._sample.name, self._sample.app, size))
+ self.logger.debugv("Random filling eventsDict for sample '%s' in app '%s' with %d bytes" %
+ (self._sample.name, self._sample.app, size))
while currentSize < size:
- currentevent = updated_sample_dict[random.randint(0, sdlen-1)]
+ currentevent = updated_sample_dict[random.randint(0, sdlen - 1)]
eventsDict.append(currentevent)
currentSize += len(currentevent['_raw'])
# If we're bundlelines, create count copies of the sampleDict
elif self._sample.bundlelines:
- self.logger.debugv("Bundlelines, filling eventsDict for sample '%s' in app '%s' with %d copies of sampleDict" % (self._sample.name, self._sample.app, size))
+ self.logger.debugv(
+ "Bundlelines, filling eventsDict for sample '%s' in app '%s' with %d copies of sampleDict" %
+ (self._sample.name, self._sample.app, size))
while currentSize <= size:
sizeofsample = sum(len(sample['_raw']) for sample in updated_sample_dict)
eventsDict.extend(updated_sample_dict)
@@ -62,19 +69,22 @@ def gen(self, count, earliest, latest, samplename=None):
sizeremaining = size - currentreadsize
targetlinesize = len(updated_sample_dict[targetline]['_raw'])
if size < targetlinesize:
- self.logger.error("Size is too small for sample {}. For this interval, we need {} bytes but size of one event is {} bytes.".format(self._sample.name, size, targetlinesize))
+ self.logger.error(
+ "Size is too small for sample {}. We need {} bytes but size of one event is {} bytes.".format(
+ self._sample.name, size, targetlinesize))
break
- if targetlinesize <= sizeremaining or targetlinesize*.9 <= sizeremaining:
+ if targetlinesize <= sizeremaining or targetlinesize * .9 <= sizeremaining:
currentreadsize += targetlinesize
eventsDict.append(updated_sample_dict[targetline])
else:
break
linecount += 1
- self.logger.debugv("Events fill complete for sample '%s' in app '%s' length %d" % (self._sample.name, self._sample.app, len(eventsDict)))
+ self.logger.debugv("Events fill complete for sample '%s' in app '%s' length %d" %
+ (self._sample.name, self._sample.app, len(eventsDict)))
# Ignore token replacement here because we completed it at the beginning of event generation
GeneratorPlugin.build_events(self, eventsDict, startTime, earliest, latest, ignore_tokens=True)
def load():
- return PerDayVolumeGenerator
\ No newline at end of file
+ return PerDayVolumeGenerator
diff --git a/splunk_eventgen/lib/plugins/generator/replay.py b/splunk_eventgen/lib/plugins/generator/replay.py
index 8854f392..5f1a6900 100644
--- a/splunk_eventgen/lib/plugins/generator/replay.py
+++ b/splunk_eventgen/lib/plugins/generator/replay.py
@@ -1,12 +1,12 @@
# TODO Add timestamp detection for common timestamp format
from __future__ import division
-from generatorplugin import GeneratorPlugin
-import datetime, time
-import re
-from eventgentimestamp import EventgenTimestamp
+import datetime
+import time
+from eventgentimestamp import EventgenTimestamp
+from generatorplugin import GeneratorPlugin
class ReplayGenerator(GeneratorPlugin):
@@ -22,14 +22,12 @@ def __init__(self, sample):
self._currentevent = 0
self._timeSinceSleep = datetime.timedelta()
- self._times = [ ]
-
-
+ self._times = []
def set_time_and_send(self, rpevent, event_time, earliest, latest):
# temporary time append
rpevent['_raw'] = rpevent['_raw'][:-1]
- rpevent['_time'] = (event_time - datetime.datetime(1970,1,1)).total_seconds()
+ rpevent['_time'] = (event_time - datetime.datetime(1970, 1, 1)).total_seconds()
event = rpevent['_raw']
@@ -38,10 +36,10 @@ def set_time_and_send(self, rpevent, event_time, earliest, latest):
# picked from a random line in that file
mvhash = {}
- ## Iterate tokens
+ # Iterate tokens
for token in self._sample.tokens:
token.mvhash = mvhash
- if token.replacementType in ['timestamp', 'replaytimestamp'] :
+ if token.replacementType in ['timestamp', 'replaytimestamp']:
event = token.replace(event, et=event_time, lt=event_time, s=self._sample)
else:
event = token.replace(event, s=self._sample)
@@ -68,7 +66,8 @@ def gen(self, count, earliest, latest, samplename=None):
self.backfill_time = self._sample.get_backfill_time(self.current_time)
if not self._sample.backfill or self._sample.backfilldone:
- self.backfill_time = EventgenTimestamp.get_random_timestamp_backfill(earliest, latest, self._sample.earliest, self._sample.latest)
+ self.backfill_time = EventgenTimestamp.get_random_timestamp_backfill(
+ earliest, latest, self._sample.earliest, self._sample.latest)
for line in self._sample.get_loaded_sample():
# Add newline to a raw line if necessary
@@ -81,27 +80,29 @@ def gen(self, count, earliest, latest, samplename=None):
hostRegex = line.get('hostRegex', self._sample.hostRegex)
source = line.get('source', self._sample.source)
sourcetype = line.get('sourcetype', self._sample.sourcetype)
- rpevent = {'_raw': line['_raw'], 'index': index, 'host': host, 'hostRegex': hostRegex,
- 'source': source, 'sourcetype': sourcetype}
+ rpevent = {
+ '_raw': line['_raw'], 'index': index, 'host': host, 'hostRegex': hostRegex, 'source': source,
+ 'sourcetype': sourcetype}
except:
if line[-1] != '\n':
line += '\n'
- rpevent = {'_raw': line, 'index': self._sample.index, 'host': self._sample.host,
- 'hostRegex': self._sample.hostRegex,
- 'source': self._sample.source, 'sourcetype': self._sample.sourcetype}
+ rpevent = {
+ '_raw': line, 'index': self._sample.index, 'host': self._sample.host, 'hostRegex':
+ self._sample.hostRegex, 'source': self._sample.source, 'sourcetype': self._sample.sourcetype}
# If timestamp doesn't exist, the sample file should be fixed to include timestamp for every event.
try:
current_event_timestamp = self._sample.getTSFromEvent(rpevent[self._sample.timeField])
- except Exception as e:
+ except Exception:
try:
current_event_timestamp = self._sample.getTSFromEvent(line[self._sample.timeField])
- except Exception as e:
+ except Exception:
try:
- self.logger.debug("Sample timeField {} failed to locate. Trying to locate _time field.".format(self._sample.timeField))
+ self.logger.debug("Sample timeField {} failed to locate. Trying to locate _time field.".format(
+ self._sample.timeField))
current_event_timestamp = self._sample.getTSFromEvent(line["_time"])
- except Exception as e:
+ except Exception:
self.logger.exception("Extracting timestamp from an event failed.")
continue
@@ -130,5 +131,6 @@ def gen(self, count, earliest, latest, samplename=None):
self._out.flush(endOfInterval=True)
return
+
def load():
return ReplayGenerator
diff --git a/splunk_eventgen/lib/plugins/generator/weblog.py b/splunk_eventgen/lib/plugins/generator/weblog.py
index 39cda67f..b6c0e841 100755
--- a/splunk_eventgen/lib/plugins/generator/weblog.py
+++ b/splunk_eventgen/lib/plugins/generator/weblog.py
@@ -1,7 +1,9 @@
from __future__ import division
-from generatorplugin import GeneratorPlugin
-import time
+
import random
+import time
+
+from generatorplugin import GeneratorPlugin
class WeblogGenerator(GeneratorPlugin):
@@ -30,25 +32,22 @@ def __init__(self, sample):
def gen(self, count, earliest, latest, **kwargs):
# logger.debug("weblog: external_ips_len: %s webhosts_len: %s useragents_len: %s webserverstatus_len: %s" % \
- # (self.external_ips_len, self.webhosts_len, self.useragents_len, self.webserverstatus_len))
- l = [ { '_raw': ('%s %s - - [%s] '
- + '"GET /product.screen?product_id=HolyGouda&JSESSIONID=SD3SL1FF7ADFF8 HTTP 1.1" '
- + '%s %s "http://shop.buttercupgames.com/cart.do?action=view&itemId=HolyGouda" '
- + '"%s" %s') % \
- (self.external_ips[random.randint(0, self.external_ips_len-1)],
- self.webhosts[random.randint(0, self.webhosts_len-1)],
- latest.strftime('%d/%b/%Y %H:%M:%S:%f'),
- self.webserverstatus[random.randint(0, self.webserverstatus_len-1)],
- random.randint(100, 1000),
- self.useragents[random.randint(0, self.useragents_len-1)],
- random.randint(200, 2000)),
- 'index': self._sample.index,
- 'sourcetype': self._sample.sourcetype,
- 'host': self._sample.host,
- 'source': self._sample.source,
- '_time': int(time.mktime(latest.timetuple())) } for i in xrange(count) ]
-
- self._out.bulksend(l)
+ # (self.external_ips_len, self.webhosts_len, self.useragents_len, self.webserverstatus_len))
+ payload = [{
+ '_raw':
+ ('%s %s - - [%s] ' + '"GET /product.screen?product_id=HolyGouda&JSESSIONID=SD3SL1FF7ADFF8 HTTP 1.1" ' +
+ '%s %s "http://shop.buttercupgames.com/cart.do?action=view&itemId=HolyGouda" ' + '"%s" %s') %
+ (self.external_ips[random.randint(0, self.external_ips_len - 1)], self.webhosts[random.randint(
+ 0, self.webhosts_len - 1)], latest.strftime('%d/%b/%Y %H:%M:%S:%f'),
+ self.webserverstatus[random.randint(0, self.webserverstatus_len - 1)], random.randint(100, 1000),
+ self.useragents[random.randint(0, self.useragents_len - 1)], random.randint(200, 2000)), 'index':
+ self._sample.index, 'sourcetype':
+ self._sample.sourcetype, 'host':
+ self._sample.host, 'source':
+ self._sample.source, '_time':
+ int(time.mktime(latest.timetuple()))} for i in xrange(count)]
+
+ self._out.bulksend(payload)
return 0
diff --git a/splunk_eventgen/lib/plugins/generator/windbag.py b/splunk_eventgen/lib/plugins/generator/windbag.py
index a8276382..90d2cd8a 100644
--- a/splunk_eventgen/lib/plugins/generator/windbag.py
+++ b/splunk_eventgen/lib/plugins/generator/windbag.py
@@ -1,8 +1,10 @@
from __future__ import division
-from generatorplugin import GeneratorPlugin
import datetime
from datetime import timedelta
+from generatorplugin import GeneratorPlugin
+
+
class WindbagGenerator(GeneratorPlugin):
def __init__(self, sample):
GeneratorPlugin.__init__(self, sample)
@@ -13,8 +15,8 @@ def gen(self, count, earliest, latest, samplename=None):
count = 60
time_interval = timedelta.total_seconds((latest - earliest)) / count
for i in xrange(count):
- current_time_object = earliest + datetime.timedelta(0, time_interval*(i+1))
- msg = '{0} -0700 WINDBAG Event {1} of {2}'.format(current_time_object, (i+1), count)
+ current_time_object = earliest + datetime.timedelta(0, time_interval * (i + 1))
+ msg = '{0} -0700 WINDBAG Event {1} of {2}'.format(current_time_object, (i + 1), count)
self._out.send(msg)
return 0
diff --git a/splunk_eventgen/lib/plugins/output/awss3.py b/splunk_eventgen/lib/plugins/output/awss3.py
index 0e9210d9..223d90fa 100644
--- a/splunk_eventgen/lib/plugins/output/awss3.py
+++ b/splunk_eventgen/lib/plugins/output/awss3.py
@@ -1,16 +1,20 @@
from __future__ import division
-from outputplugin import OutputPlugin
+
+import datetime
+import logging
+import threading
+import uuid
+
import requests
+
+from outputplugin import OutputPlugin
+
try:
import boto3
import botocore.exceptions
boto_imported = True
except ImportError:
boto_imported = False
-import uuid
-import datetime
-import threading
-import logging
def threaded(fn):
@@ -31,18 +35,14 @@ class AwsS3OutputPlugin(OutputPlugin):
name = 'awsS3'
useOutputQueue = False
# MAXQUEUELENGTH = 100
- validSettings = ['awsS3BucketName', 'awsS3CompressionType',
- 'awsS3EventType', 'awsS3ObjectPrefix',
- 'awsS3ObjectSuffix', 'awsRegion', 'awsKeyId',
- 'awsSecretKey', 'awsS3EventPerKey']
- defaultableSettings = ['awsKeyId', 'awsSecretKey', 'awsS3EventType',
- 'awsS3CompressionType', 'awsS3ObjectPrefix',
- 'awsS3ObjectSuffix']
+ validSettings = [
+ 'awsS3BucketName', 'awsS3CompressionType', 'awsS3EventType', 'awsS3ObjectPrefix', 'awsS3ObjectSuffix',
+ 'awsRegion', 'awsKeyId', 'awsSecretKey', 'awsS3EventPerKey']
+ defaultableSettings = [
+ 'awsKeyId', 'awsSecretKey', 'awsS3EventType', 'awsS3CompressionType', 'awsS3ObjectPrefix', 'awsS3ObjectSuffix']
def __init__(self, sample, output_counter=None):
-
-
# Override maxQueueLength to EventPerKey so that each flush
# will generate one aws key
if sample.awsS3EventPerKey:
@@ -59,17 +59,15 @@ def __init__(self, sample, output_counter=None):
# Bind passed in samples to the outputter.
self.awsS3compressiontype = sample.awsS3CompressionType if hasattr(
- sample,
- 'awsS3CompressionType') and sample.awsS3CompressionType else None
- self.awsS3eventtype = sample.awsS3EventType if hasattr(
- sample, 'awsS3EventType') and sample.awsS3EventType else 'syslog'
+ sample, 'awsS3CompressionType') and sample.awsS3CompressionType else None
+ self.awsS3eventtype = sample.awsS3EventType if hasattr(sample,
+ 'awsS3EventType') and sample.awsS3EventType else 'syslog'
self.awsS3objectprefix = sample.awsS3ObjectPrefix if hasattr(
sample, 'awsS3ObjectPrefix') and sample.awsS3ObjectPrefix else ""
self.awsS3objectsuffix = sample.awsS3ObjectSuffix if hasattr(
sample, 'awsS3ObjectSuffix') and sample.awsS3ObjectSuffix else ""
self.awsS3bucketname = sample.awsS3BucketName
- self.logger.debug("Setting up the connection pool for %s in %s" %
- (self._sample.name, self._app))
+ self.logger.debug("Setting up the connection pool for %s in %s" % (self._sample.name, self._app))
self._client = None
self._createConnections(sample)
self.logger.debug("Finished init of awsS3 plugin.")
@@ -77,11 +75,8 @@ def __init__(self, sample, output_counter=None):
def _createConnections(self, sample):
try:
if hasattr(sample, 'awsKeyId') and hasattr(sample, 'awsSecretKey'):
- self._client = boto3.client(
- "s3",
- region_name=sample.awsRegion,
- aws_access_key_id=sample.awsKeyId,
- aws_secret_access_key=sample.awsSecretKey)
+ self._client = boto3.client("s3", region_name=sample.awsRegion, aws_access_key_id=sample.awsKeyId,
+ aws_secret_access_key=sample.awsSecretKey)
if self._client is None:
msg = '''
[your_eventgen_stanza]
@@ -89,10 +84,9 @@ def _createConnections(self, sample):
awsSecretKey = YOUR_SECRET_KEY
'''
- self.logger.error(
- "Failed for init boto3 client: %s, you should define correct 'awsKeyId'\
+ self.logger.error("Failed for init boto3 client: %s, you should define correct 'awsKeyId'\
and 'awsSecretKey' in eventgen conf %s" % msg)
- raise
+ raise Exception(msg)
else:
self._client = boto3.client('s3', region_name=sample.awsRegion)
except Exception as e:
@@ -109,38 +103,29 @@ def _createConnections(self, sample):
'''
self.logger.error("Failed for init boto3 client, you should create "
- "'~/.aws/credentials' with credential info %s" % msg)
+ "'~/.aws/credentials' with credential info %s" % msg)
raise
self.logger.debug("Init conn done, conn = %s" % self._client)
def _sendPayloads(self, payload):
- currentreadsize = 0
- currentreadevent = 0
- stringpayload = []
- totalbytesexpected = 0
- totalbytessent = 0
numberevents = len(payload)
self.logger.debug("Sending %s events to s3 key" % numberevents)
self._transmitEvents(payload)
def _transmitEvents(self, payloadstring):
- self.logger.debug("Transmission called with payloadstring event number: %d "
- % len(payloadstring))
+ self.logger.debug("Transmission called with payloadstring event number: %d " % len(payloadstring))
records = "".join(payloadstring)
# Different key prefix for different log type
if self.awsS3eventtype == 'elbaccesslog':
- s3keyname = self.awsS3objectprefix + datetime.datetime.utcnow(
- ).strftime("%Y%m%dT%H%MZ") + '_' + str(uuid.uuid1(
- )) + self.awsS3objectsuffix
+ s3keyname = self.awsS3objectprefix + datetime.datetime.utcnow().strftime("%Y%m%dT%H%MZ") + '_' + str(
+ uuid.uuid1()) + self.awsS3objectsuffix
elif self.awsS3eventtype == 's3accesslog':
- s3keyname = self.awsS3objectprefix + datetime.datetime.utcnow(
- ).strftime("%Y-%m-%d-%H-%M-%S") + '-' + str(uuid.uuid1()).replace(
- '-', '').upper()[0:15] + self.awsS3objectsuffix
+ s3keyname = self.awsS3objectprefix + datetime.datetime.utcnow().strftime("%Y-%m-%d-%H-%M-%S") + '-' + str(
+ uuid.uuid1()).replace('-', '').upper()[0:15] + self.awsS3objectsuffix
else:
- s3keyname = self.awsS3objectprefix + datetime.datetime.utcnow(
- ).isoformat() + str(uuid.uuid1()) + self.awsS3objectsuffix
- self.logger.debugv("Uploading %d events into s3 key: %s " %
- (len(records), s3keyname))
+ s3keyname = self.awsS3objectprefix + datetime.datetime.utcnow().isoformat() + str(
+ uuid.uuid1()) + self.awsS3objectsuffix
+ self.logger.debug("Uploading %d events into s3 key: %s " % (len(records), s3keyname))
if self.awsS3compressiontype == 'gz':
import StringIO
import gzip
@@ -149,14 +134,11 @@ def _transmitEvents(self, payloadstring):
f.write(records)
records = out.getvalue()
try:
- response = self._client.put_object(Bucket=self.awsS3bucketname,
- Key=s3keyname,
- Body=records)
- self.logger.debugv("response = %s" % response)
+ response = self._client.put_object(Bucket=self.awsS3bucketname, Key=s3keyname, Body=records)
+ self.logger.debug("response = %s" % response)
except Exception as e:
self.logger.error("Failed for exception: %s" % e)
- self.logger.debugv("Failed sending events to payload: %s" %
- (payloadstring))
+ self.logger.debug("Failed sending events to payload: %s" % (payloadstring))
raise e
def flush(self, q):
@@ -167,12 +149,10 @@ def flush(self, q):
self.logger.debug("Currently being called with %d events" % len(q))
for event in q:
if event.get('_raw') is None:
- self.logger.error(
- 'failure outputting event, does not contain _raw')
+ self.logger.error('failure outputting event, does not contain _raw')
else:
payload.append(event['_raw'])
- self.logger.debug(
- "Finished processing events, sending all to AWS S3")
+ self.logger.debug("Finished processing events, sending all to AWS S3")
self._sendPayloads(payload)
except Exception as e:
import traceback
diff --git a/splunk_eventgen/lib/plugins/output/devnull.py b/splunk_eventgen/lib/plugins/output/devnull.py
index 70bbdde6..faf26a81 100755
--- a/splunk_eventgen/lib/plugins/output/devnull.py
+++ b/splunk_eventgen/lib/plugins/output/devnull.py
@@ -1,7 +1,10 @@
from __future__ import division
-from outputplugin import OutputPlugin
+
import logging
+from outputplugin import OutputPlugin
+
+
class DevNullOutputPlugin(OutputPlugin):
name = 'devnull'
MAXQUEUELENGTH = 1000
@@ -21,6 +24,7 @@ def flush(self, q):
def _setup_logging(self):
self.logger = logging.getLogger('eventgen_devnullout')
+
def load():
"""Returns an instance of the plugin"""
return DevNullOutputPlugin
diff --git a/splunk_eventgen/lib/plugins/output/file.py b/splunk_eventgen/lib/plugins/output/file.py
index d04b23a1..3287c49d 100644
--- a/splunk_eventgen/lib/plugins/output/file.py
+++ b/splunk_eventgen/lib/plugins/output/file.py
@@ -1,9 +1,11 @@
# Note as implemented this plugin is not threadsafe, file should only be used with one output worker
from __future__ import division
-from outputplugin import OutputPlugin
-import os
+
import logging
+import os
+
+from outputplugin import OutputPlugin
class FileOutputPlugin(OutputPlugin):
@@ -11,28 +13,29 @@ class FileOutputPlugin(OutputPlugin):
MAXQUEUELENGTH = 10
useOutputQueue = False
- validSettings = [ 'fileMaxBytes', 'fileBackupFiles' ]
- intSettings = [ 'fileMaxBytes', 'fileBackupFiles' ]
+ validSettings = ['fileMaxBytes', 'fileBackupFiles']
+ intSettings = ['fileMaxBytes', 'fileBackupFiles']
def __init__(self, sample, output_counter=None):
OutputPlugin.__init__(self, sample, output_counter)
- if sample.fileName == None:
+ if sample.fileName is None:
self.logger.error('outputMode file but file not specified for sample %s' % self._sample.name)
raise ValueError('outputMode file but file not specified for sample %s' % self._sample.name)
-
+
self._file = sample.pathParser(sample.fileName)
self._fileMaxBytes = sample.fileMaxBytes
self._fileBackupFiles = sample.fileBackupFiles
self._fileHandle = open(self._file, 'a')
self._fileLength = os.stat(self._file).st_size
- self.logger.debug("Configured to log to '%s' with maxBytes '%s' with backupCount '%s'" % \
- (self._file, self._fileMaxBytes, self._fileBackupFiles))
+ self.logger.debug("Configured to log to '%s' with maxBytes '%s' with backupCount '%s'" %
+ (self._file, self._fileMaxBytes, self._fileBackupFiles))
def flush(self, q):
if len(q) > 0:
- self.logger.debug("Flushing output for sample '%s' in app '%s' for queue '%s'" % (self._sample.name, self._app, self._sample.source))
+ self.logger.debug("Flushing output for sample '%s' in app '%s' for queue '%s'" %
+ (self._sample.name, self._app, self._sample.source))
# Loop through all the messages and build the long string, write once for each flush
# This may cause the file exceed the maxFileBytes a little bit but will greatly improve the performance
@@ -52,19 +55,22 @@ def flush(self, q):
if self._fileLength > self._fileMaxBytes:
self._fileHandle.flush()
self._fileHandle.close()
- if os.path.exists(self._file+'.'+str(self._fileBackupFiles)):
- self.logger.debug('File Output: Removing file: %s' % self._file+'.'+str(self._fileBackupFiles))
- os.unlink(self._file+'.'+str(self._fileBackupFiles))
+ if os.path.exists(self._file + '.' + str(self._fileBackupFiles)):
+ self.logger.debug('File Output: Removing file: %s' % self._file + '.' +
+ str(self._fileBackupFiles))
+ os.unlink(self._file + '.' + str(self._fileBackupFiles))
for x in range(1, self._fileBackupFiles)[::-1]:
- self.logger.debug('File Output: Checking for file: %s' % self._file+'.'+str(x))
- if os.path.exists(self._file+'.'+str(x)):
- self.logger.debug('File Output: Renaming file %s to %s' % (self._file+'.'+str(x), self._file+'.'+str(x+1)))
- os.rename(self._file+'.'+str(x), self._file+'.'+str(x+1))
- os.rename(self._file, self._file+'.1')
+ self.logger.debug('File Output: Checking for file: %s' % self._file + '.' + str(x))
+ if os.path.exists(self._file + '.' + str(x)):
+ self.logger.debug('File Output: Renaming file %s to %s' % (self._file + '.' + str(x),
+ self._file + '.' + str(x + 1)))
+ os.rename(self._file + '.' + str(x), self._file + '.' + str(x + 1))
+ os.rename(self._file, self._file + '.1')
self._fileHandle = open(self._file, 'w')
self._fileLength = 0
except IndexError:
- self.logger.warning("IndexError when writting for app '%s' sample '%s'" % (self._app, self._sample.name))
+ self.logger.warning(
+ "IndexError when writting for app '%s' sample '%s'" % (self._app, self._sample.name))
if not self._fileHandle.closed:
self._fileHandle.flush()
@@ -75,6 +81,7 @@ def flush(self, q):
def _setup_logging(self):
self.logger = logging.getLogger('eventgen')
+
def load():
"""Returns an instance of the plugin"""
return FileOutputPlugin
diff --git a/splunk_eventgen/lib/plugins/output/httpevent.py b/splunk_eventgen/lib/plugins/output/httpevent.py
index 107371c5..81082a1c 100644
--- a/splunk_eventgen/lib/plugins/output/httpevent.py
+++ b/splunk_eventgen/lib/plugins/output/httpevent.py
@@ -1,8 +1,13 @@
from __future__ import division
+
+import logging
+import random
+import urllib
+
from outputplugin import OutputPlugin
+
try:
import requests
- import requests_futures
from requests import Session
from requests_futures.sessions import FuturesSession
from concurrent.futures import ThreadPoolExecutor
@@ -12,17 +17,17 @@
import ujson as json
except:
import json
-import random
-import urllib
-import logging
+
class NoServers(Exception):
- def __init__(self,*args,**kwargs):
- Exception.__init__(self,*args,**kwargs)
+ def __init__(self, *args, **kwargs):
+ Exception.__init__(self, *args, **kwargs)
+
class BadConnection(Exception):
- def __init__(self,*args,**kwargs):
- Exception.__init__(self,*args,**kwargs)
+ def __init__(self, *args, **kwargs):
+ Exception.__init__(self, *args, **kwargs)
+
class HTTPEventOutputPlugin(OutputPlugin):
'''
@@ -30,9 +35,9 @@ class HTTPEventOutputPlugin(OutputPlugin):
to splunk through the HTTP event input. In order to use this output plugin,
you will need to supply an attribute 'httpeventServers' as a valid json object.
this json object should look like the following:
-
+
{servers:[{ protocol:http/https, address:127.0.0.1, port:8088, key:12345-12345-123123123123123123}]}
-
+
'''
name = 'httpevent'
MAXQUEUELENGTH = 1000
@@ -44,11 +49,11 @@ class HTTPEventOutputPlugin(OutputPlugin):
def __init__(self, sample, output_counter=None):
OutputPlugin.__init__(self, sample, output_counter)
- #TODO: make workers a param that can be set in eventgen.conf
+ # TODO: make workers a param that can be set in eventgen.conf
def _setup_REST_workers(self, session=None, workers=10):
- #disable any "requests" warnings
+ # disable any "requests" warnings
requests.packages.urllib3.disable_warnings()
- #Bind passed in samples to the outputter.
+ # Bind passed in samples to the outputter.
self.lastsourcetype = None
if not session:
session = Session()
@@ -67,8 +72,8 @@ def _urlencode(value):
@staticmethod
def _bg_convert_json(sess, resp):
'''
- Takes a futures session object, and will set the data to a parsed json output. Use this as a background task
- for the sesssion queue. Example: future = session.get('http://httpbin.org/get', background_callback=_bg_convert_json)
+ Takes a futures session object, and sets the data to a parsed json output. Use this as a background task for the
+ session queue. Example: future = session.get('http://httpbin.org/get', background_callback=_bg_convert_json)
:param sess: futures session object. Automatically called on a background_callback as aruguments.
:param resp: futures resp object. Automatically called on a background_callback as aruguments.
:return:
@@ -83,12 +88,14 @@ def _bg_convert_json(sess, resp):
def updateConfig(self, config):
OutputPlugin.updateConfig(self, config)
try:
- if hasattr(self.config, 'httpeventServers') == False:
+ if hasattr(self.config, 'httpeventServers') is False:
if hasattr(self._sample, 'httpeventServers'):
self.config.httpeventServers = self._sample.httpeventServers
else:
- self.logger.error('outputMode httpevent but httpeventServers not specified for sample %s' % self._sample.name)
- raise NoServers('outputMode httpevent but httpeventServers not specified for sample %s' % self._sample.name)
+ self.logger.error(
+ 'outputMode httpevent but httpeventServers not specified for sample %s' % self._sample.name)
+ raise NoServers(
+ 'outputMode httpevent but httpeventServers not specified for sample %s' % self._sample.name)
# set default output mode to round robin
if hasattr(self.config, 'httpeventOutputMode') and self.config.httpeventOutputMode:
self.httpeventoutputmode = config.httpeventOutputMode
@@ -106,9 +113,9 @@ def updateConfig(self, config):
self.httpeventmaxsize = 10000
self.logger.debug("Currentmax size: %s " % self.httpeventmaxsize)
if isinstance(config.httpeventServers, str):
- self.httpeventServers = json.loads(config.httpeventServers)
+ self.httpeventServers = json.loads(config.httpeventServers)
else:
- self.httpeventServers = config.httpeventServers
+ self.httpeventServers = config.httpeventServers
self.logger.debug("Setting up the connection pool for %s in %s" % (self._sample.name, self._app))
self.createConnections()
self.logger.debug("Pool created.")
@@ -116,27 +123,40 @@ def updateConfig(self, config):
except Exception as e:
self.logger.exception(e)
-
def createConnections(self):
self.serverPool = []
if self.httpeventServers:
for server in self.httpeventServers.get('servers'):
if not server.get('address'):
- self.logger.error('requested a connection to a httpevent server, but no address specified for sample %s' % self._sample.name)
- raise ValueError('requested a connection to a httpevent server, but no address specified for sample %s' % self._sample.name)
+ self.logger.error(
+ 'requested a connection to a httpevent server, but no address specified for sample %s' %
+ self._sample.name)
+ raise ValueError(
+ 'requested a connection to a httpevent server, but no address specified for sample %s' %
+ self._sample.name)
if not server.get('port'):
- self.logger.error('requested a connection to a httpevent server, but no port specified for server %s' % server)
- raise ValueError('requested a connection to a httpevent server, but no port specified for server %s' % server)
+ self.logger.error(
+ 'requested a connection to a httpevent server, but no port specified for server %s' % server)
+ raise ValueError(
+ 'requested a connection to a httpevent server, but no port specified for server %s' % server)
if not server.get('key'):
- self.logger.error('requested a connection to a httpevent server, but no key specified for server %s' % server)
- raise ValueError('requested a connection to a httpevent server, but no key specified for server %s' % server)
+ self.logger.error(
+ 'requested a connection to a httpevent server, but no key specified for server %s' % server)
+ raise ValueError(
+ 'requested a connection to a httpevent server, but no key specified for server %s' % server)
if not ((server.get('protocol') == 'http') or (server.get('protocol') == 'https')):
- self.logger.error('requested a connection to a httpevent server, but no protocol specified for server %s' % server)
- raise ValueError('requested a connection to a httpevent server, but no protocol specified for server %s' % server)
- self.logger.debug("Validation Passed, Creating a requests object for server: %s" % server.get('address'))
+ self.logger.error(
+ 'requested a connection to a httpevent server, but no protocol specified for server %s' %
+ server)
+ raise ValueError(
+ 'requested a connection to a httpevent server, but no protocol specified for server %s' %
+ server)
+ self.logger.debug(
+ "Validation Passed, Creating a requests object for server: %s" % server.get('address'))
setserver = {}
- setserver['url'] = "%s://%s:%s/services/collector" % (server.get('protocol'), server.get('address'), server.get('port'))
+ setserver['url'] = "%s://%s:%s/services/collector" % (server.get('protocol'), server.get('address'),
+ server.get('port'))
setserver['header'] = "Splunk %s" % server.get('key')
self.logger.debug("Adding server set to pool, server: %s" % setserver)
self.serverPool.append(setserver)
@@ -151,15 +171,15 @@ def _sendHTTPEvents(self, payload):
numberevents = len(payload)
self.logger.debug("Sending %s events to splunk" % numberevents)
for line in payload:
- self.logger.debugv("line: %s " % line)
+ self.logger.debug("line: %s " % line)
targetline = json.dumps(line)
- self.logger.debugv("targetline: %s " % targetline)
+ self.logger.debug("targetline: %s " % targetline)
targetlinesize = len(targetline)
totalbytesexpected += targetlinesize
if (int(currentreadsize) + int(targetlinesize)) <= int(self.httpeventmaxsize):
stringpayload = stringpayload + targetline
currentreadsize = currentreadsize + targetlinesize
- self.logger.debugv("stringpayload: %s " % stringpayload)
+ self.logger.debug("stringpayload: %s " % stringpayload)
else:
self.logger.debug("Max size for payload hit, sending to splunk then continuing.")
try:
@@ -173,7 +193,9 @@ def _sendHTTPEvents(self, payload):
else:
try:
totalbytessent += len(stringpayload)
- self.logger.debug("End of for loop hit for sending events to splunk, total bytes sent: %s ---- out of %s -----" % (totalbytessent, totalbytesexpected))
+ self.logger.debug(
+ "End of for loop hit for sending events to splunk, total bytes sent: %s ---- out of %s -----" %
+ (totalbytessent, totalbytesexpected))
self._transmitEvents(stringpayload)
except Exception as e:
self.logger.exception(e)
@@ -181,7 +203,7 @@ def _sendHTTPEvents(self, payload):
def _transmitEvents(self, payloadstring):
targetServer = []
- self.logger.debugv("Transmission called with payloadstring: %s " % payloadstring)
+ self.logger.debug("Transmission called with payloadstring: %s " % payloadstring)
if self.httpeventoutputmode == "mirror":
targetServer = self.serverPool
else:
@@ -194,12 +216,15 @@ def _transmitEvents(self, payloadstring):
headers['content-type'] = 'application/json'
try:
payloadsize = len(payloadstring)
- #response = requests.post(url, data=payloadstring, headers=headers, verify=False)
- self.active_sessions.append(self.session.post(url=url, data=payloadstring, headers=headers, verify=False))
+ # response = requests.post(url, data=payloadstring, headers=headers, verify=False)
+ self.active_sessions.append(
+ self.session.post(url=url, data=payloadstring, headers=headers, verify=False))
except Exception as e:
self.logger.error("Failed for exception: %s" % e)
- self.logger.error("Failed sending events to url: %s sourcetype: %s size: %s" % (url, self.lastsourcetype, payloadsize))
- self.logger.debugv("Failed sending events to url: %s headers: %s payload: %s" % (url, headers, payloadstring))
+ self.logger.error("Failed sending events to url: %s sourcetype: %s size: %s" %
+ (url, self.lastsourcetype, payloadsize))
+ self.logger.debug(
+ "Failed sending events to url: %s headers: %s payload: %s" % (url, headers, payloadstring))
raise e
def flush(self, q):
@@ -208,39 +233,37 @@ def flush(self, q):
if len(q) > 0:
try:
payload = []
- lastsourcetype = ""
- payloadsize = 0
self.logger.debug("Currently being called with %d events" % len(q))
for event in q:
- self.logger.debugv("HTTPEvent proccessing event: %s" % event)
+ self.logger.debug("HTTPEvent proccessing event: %s" % event)
payloadFragment = {}
- if event.get('_raw') == None or event['_raw'] == "\n":
+ if event.get('_raw') is None or event['_raw'] == "\n":
self.logger.error('failure outputting event, does not contain _raw')
else:
- self.logger.debugv("Event contains _raw, attempting to process...")
+ self.logger.debug("Event contains _raw, attempting to process...")
payloadFragment['event'] = event['_raw']
if event.get('source'):
- self.logger.debugv("Event contains source, adding to httpevent event")
+ self.logger.debug("Event contains source, adding to httpevent event")
payloadFragment['source'] = event['source']
if event.get('sourcetype'):
- self.logger.debugv("Event contains sourcetype, adding to httpevent event")
+ self.logger.debug("Event contains sourcetype, adding to httpevent event")
payloadFragment['sourcetype'] = event['sourcetype']
self.lastsourcetype = event['sourcetype']
if event.get('host'):
- self.logger.debugv("Event contains host, adding to httpevent event")
+ self.logger.debug("Event contains host, adding to httpevent event")
payloadFragment['host'] = event['host']
if event.get('_time'):
# make sure _time can be an epoch timestamp
try:
float(event.get("_time"))
- self.logger.debugv("Event contains _time, adding to httpevent event")
+ self.logger.debug("Event contains _time, adding to httpevent event")
payloadFragment['time'] = event['_time']
except:
self.logger.error("Timestamp not in epoch format, ignoring event: {0}".format(event))
if event.get('index'):
- self.logger.debugv("Event contains index, adding to httpevent event")
+ self.logger.debug("Event contains index, adding to httpevent event")
payloadFragment['index'] = event['index']
- self.logger.debugv("Full payloadFragment: %s" % json.dumps(payloadFragment))
+ self.logger.debug("Full payloadFragment: %s" % json.dumps(payloadFragment))
payload.append(payloadFragment)
self.logger.debug("Finished processing events, sending all to splunk")
self._sendHTTPEvents(payload)
@@ -250,8 +273,10 @@ def flush(self, q):
if not response.raise_for_status():
self.logger.debug("Payload successfully sent to httpevent server.")
else:
- self.logger.error("Server returned an error while trying to send, response code: %s" % response.status_code)
- raise BadConnection("Server returned an error while sending, response code: %s" % response.status_code)
+ self.logger.error("Server returned an error while trying to send, response code: %s" %
+ response.status_code)
+ raise BadConnection(
+ "Server returned an error while sending, response code: %s" % response.status_code)
else:
self.logger.debug("Ignoring response from HTTP server, leaving httpevent outputter")
except Exception as e:
@@ -260,6 +285,7 @@ def flush(self, q):
def _setup_logging(self):
self.logger = logging.getLogger('eventgen_httpeventout')
+
def load():
"""Returns an instance of the plugin"""
return HTTPEventOutputPlugin
diff --git a/splunk_eventgen/lib/plugins/output/modinput.py b/splunk_eventgen/lib/plugins/output/modinput.py
index ac748396..cd2b792b 100644
--- a/splunk_eventgen/lib/plugins/output/modinput.py
+++ b/splunk_eventgen/lib/plugins/output/modinput.py
@@ -4,10 +4,13 @@
# from eventgenoutputtemplates import OutputTemplate
from __future__ import division
-from outputplugin import OutputPlugin
+
+import logging
import sys
from xml.sax.saxutils import escape
-import logging
+
+from outputplugin import OutputPlugin
+
class ModInputOutputPlugin(OutputPlugin):
name = 'modinput'
@@ -45,6 +48,7 @@ def flush(self, q):
def _setup_logging(self):
self.logger = logging.getLogger('eventgen')
+
def load():
"""Returns an instance of the plugin"""
- return ModInputOutputPlugin
\ No newline at end of file
+ return ModInputOutputPlugin
diff --git a/splunk_eventgen/lib/plugins/output/s2s.py b/splunk_eventgen/lib/plugins/output/s2s.py
index 26f132e3..6798dbcc 100644
--- a/splunk_eventgen/lib/plugins/output/s2s.py
+++ b/splunk_eventgen/lib/plugins/output/s2s.py
@@ -1,9 +1,10 @@
from __future__ import division
-from outputplugin import OutputPlugin
-import struct
-import socket
import logging
+import socket
+import struct
+
+from outputplugin import OutputPlugin
class S2S:
@@ -60,7 +61,7 @@ def _encode_string(self, tosend=''):
by a null terminated string.
"""
tosend = str(tosend)
- return struct.pack('!I%ds' % (len(tosend)+1), len(tosend)+1, tosend)
+ return struct.pack('!I%ds' % (len(tosend) + 1), len(tosend) + 1, tosend)
def _encode_key_value(self, key='', value=''):
"""
@@ -74,30 +75,29 @@ def _encode_event(self, index='main', host='', source='', sourcetype='', _raw='_
# Create signature
sig = self._encode_sig()
- msg_size = len(struct.pack('!I', 0)) # size of unsigned 32 bit integer, which is the count of map entries
+ msg_size = len(struct.pack('!I', 0)) # size of unsigned 32 bit integer, which is the count of map entries
maps = 1
# May not have these, so set them first
encoded_source = False
encoded_sourcetype = False
encoded_host = False
- encoded_index = False
# Encode source
if len(source) > 0:
- encoded_source = self._encode_key_value('MetaData:Source', 'source::'+source)
+ encoded_source = self._encode_key_value('MetaData:Source', 'source::' + source)
maps += 1
msg_size += len(encoded_source)
# Encode sourcetype
if len(sourcetype) > 0:
- encoded_sourcetype = self._encode_key_value('MetaData:Sourcetype', 'sourcetype::'+sourcetype)
+ encoded_sourcetype = self._encode_key_value('MetaData:Sourcetype', 'sourcetype::' + sourcetype)
maps += 1
msg_size += len(encoded_sourcetype)
-
+
# Encode host
if len(host) > 0:
- encoded_host = self._encode_key_value('MetaData:Host', 'host::'+host)
+ encoded_host = self._encode_key_value('MetaData:Host', 'host::' + host)
maps += 1
msg_size += len(encoded_host)
@@ -105,7 +105,7 @@ def _encode_event(self, index='main', host='', source='', sourcetype='', _raw='_
encoded_index = self._encode_key_value('_MetaData:Index', index)
maps += 1
msg_size += len(encoded_index)
-
+
# Encode _raw
encoded_raw = self._encode_key_value('_raw', _raw)
msg_size += len(encoded_raw)
@@ -124,7 +124,7 @@ def _encode_event(self, index='main', host='', source='', sourcetype='', _raw='_
msg_size += len(encoded_done)
# Encode _time
- if _time != None:
+ if _time is not None:
encoded_time = self._encode_key_value('_time', _time)
msg_size += len(encoded_time)
maps += 1
@@ -163,6 +163,7 @@ def close(self):
"""
self.s.close()
+
class S2SOutputPlugin(OutputPlugin):
name = 's2s'
MAXQUEUELENGTH = 10
diff --git a/splunk_eventgen/lib/plugins/output/splunkstream.py b/splunk_eventgen/lib/plugins/output/splunkstream.py
index 39fb8432..e258872c 100644
--- a/splunk_eventgen/lib/plugins/output/splunkstream.py
+++ b/splunk_eventgen/lib/plugins/output/splunkstream.py
@@ -1,10 +1,14 @@
from __future__ import division
-from outputplugin import OutputPlugin
-from xml.dom import minidom
-from collections import deque
-import httplib, httplib2
-import urllib
+
+import httplib
import logging
+import urllib
+from collections import deque
+from xml.dom import minidom
+
+import httplib2
+
+from outputplugin import OutputPlugin
class SplunkStreamOutputPlugin(OutputPlugin):
@@ -29,24 +33,31 @@ def __init__(self, sample, output_counter=None):
from eventgenconfig import Config
globals()['c'] = Config()
- self._splunkUrl, self._splunkMethod, self._splunkHost, self._splunkPort = c.getSplunkUrl(self._sample)
+ self._splunkUrl, self._splunkMethod, self._splunkHost, self._splunkPort = c.getSplunkUrl(self._sample) # noqa
self._splunkUser = self._sample.splunkUser
self._splunkPass = self._sample.splunkPass
if not self._sample.sessionKey:
try:
myhttp = httplib2.Http(disable_ssl_certificate_validation=True)
- self.logger.debug("Getting session key from '%s' with user '%s' and pass '%s'" % (self._splunkUrl + '/services/auth/login', self._splunkUser, self._splunkPass))
- response = myhttp.request(self._splunkUrl + '/services/auth/login', 'POST',
- headers = {}, body=urllib.urlencode({'username': self._splunkUser,
- 'password': self._splunkPass}))[1]
- self._sample.sessionKey = minidom.parseString(response).getElementsByTagName('sessionKey')[0].childNodes[0].nodeValue
+ self.logger.debug("Getting session key from '%s' with user '%s' and pass '%s'" %
+ (self._splunkUrl + '/services/auth/login', self._splunkUser, self._splunkPass))
+ response = myhttp.request(
+ self._splunkUrl + '/services/auth/login', 'POST', headers={}, body=urllib.urlencode({
+ 'username':
+ self._splunkUser, 'password':
+ self._splunkPass}))[1]
+ self._sample.sessionKey = minidom.parseString(response).getElementsByTagName(
+ 'sessionKey')[0].childNodes[0].nodeValue
self.logger.debug("Got new session for splunkstream, sessionKey '%s'" % self._sample.sessionKey)
except:
- self.logger.error("Error getting session key for non-SPLUNK_EMBEEDED for sample '%s'. Credentials are missing or wrong" % self._sample.name)
- raise IOError("Error getting session key for non-SPLUNK_EMBEEDED for sample '%s'. Credentials are missing or wrong" % self._sample.name)
+ self.logger.error("Error getting session key for non-SPLUNK_EMBEEDED for sample '%s'." %
+ self._sample.name + " Credentials are missing or wrong")
+ raise IOError("Error getting session key for non-SPLUNK_EMBEEDED for sample '%s'." % self._sample.name +
+ "Credentials are missing or wrong")
- self.logger.debug("Retrieved session key '%s' for Splunk session for sample %s'" % (self._sample.sessionKey, self._sample.name))
+ self.logger.debug("Retrieved session key '%s' for Splunk session for sample %s'" % (self._sample.sessionKey,
+ self._sample.name))
def flush(self, q):
if len(q) > 0:
@@ -78,7 +89,8 @@ def flush(self, q):
except KeyError:
pass
- self.logger.debug("Flushing output for sample '%s' in app '%s' for queue '%s'" % (self._sample.name, self._app, self._sample.source))
+ self.logger.debug("Flushing output for sample '%s' in app '%s' for queue '%s'" %
+ (self._sample.name, self._app, self._sample.source))
try:
if self._splunkMethod == 'https':
connmethod = httplib.HTTPSConnection
@@ -111,11 +123,14 @@ def flush(self, q):
msg = False
splunkhttp.request("POST", url, streamout, headers)
- self.logger.debug("POSTing to url %s on %s://%s:%s with sessionKey %s" \
- % (url, self._splunkMethod, self._splunkHost, self._splunkPort, self._sample.sessionKey))
+ self.logger.debug(
+ "POSTing to url %s on %s://%s:%s with sessionKey %s" %
+ (url, self._splunkMethod, self._splunkHost, self._splunkPort, self._sample.sessionKey))
except httplib.HTTPException, e:
- self.logger.error('Error connecting to Splunk for logging for sample %s. Exception "%s" Config: %s' % (self._sample.name, e.args, self))
+ self.logger.error(
+ 'Error connecting to Splunk for logging for sample %s. Exception "%s" Config: %s' %
+ (self._sample.name, e.args, self))
raise IOError('Error connecting to Splunk for logging for sample %s' % self._sample)
try:
diff --git a/splunk_eventgen/lib/plugins/output/spool.py b/splunk_eventgen/lib/plugins/output/spool.py
index cd478123..60a76d69 100644
--- a/splunk_eventgen/lib/plugins/output/spool.py
+++ b/splunk_eventgen/lib/plugins/output/spool.py
@@ -4,18 +4,21 @@
# from eventgenoutputtemplates import OutputTemplate
from __future__ import division
-from outputplugin import OutputPlugin
-import time
-import os
+
import logging
+import os
+import time
+
+from outputplugin import OutputPlugin
+
class SpoolOutputPlugin(OutputPlugin):
useOutputQueue = True
name = 'spool'
MAXQUEUELENGTH = 10
- validSettings = [ 'spoolDir', 'spoolFile' ]
- defaultableSettings = [ 'spoolDir', 'spoolFile' ]
+ validSettings = ['spoolDir', 'spoolFile']
+ defaultableSettings = ['spoolDir', 'spoolFile']
_spoolDir = None
_spoolFile = None
@@ -28,7 +31,8 @@ def __init__(self, sample, output_counter=None):
def flush(self, q):
if len(q) > 0:
- self.logger.debug("Flushing output for sample '%s' in app '%s' for queue '%s'" % (self._sample.name, self._app, self._sample.source))
+ self.logger.debug("Flushing output for sample '%s' in app '%s' for queue '%s'" %
+ (self._sample.name, self._app, self._sample.source))
# Keep trying to open destination file as it might be touched by other processes
data = ''.join(event['_raw'] for event in q if event.get('_raw'))
while True:
diff --git a/splunk_eventgen/lib/plugins/output/stdout.py b/splunk_eventgen/lib/plugins/output/stdout.py
index 3edc44df..a0ea46e1 100644
--- a/splunk_eventgen/lib/plugins/output/stdout.py
+++ b/splunk_eventgen/lib/plugins/output/stdout.py
@@ -1,7 +1,10 @@
from __future__ import division
-from outputplugin import OutputPlugin
+
import logging
+from outputplugin import OutputPlugin
+
+
class StdOutOutputPlugin(OutputPlugin):
useOutputQueue = False
name = 'stdout'
@@ -17,6 +20,7 @@ def flush(self, q):
def _setup_logging(self):
self.logger = logging.getLogger('eventgen_stdout')
+
def load():
"""Returns an instance of the plugin"""
- return StdOutOutputPlugin
\ No newline at end of file
+ return StdOutOutputPlugin
diff --git a/splunk_eventgen/lib/plugins/output/syslogout.py b/splunk_eventgen/lib/plugins/output/syslogout.py
index eb07a2e1..b1faad28 100644
--- a/splunk_eventgen/lib/plugins/output/syslogout.py
+++ b/splunk_eventgen/lib/plugins/output/syslogout.py
@@ -1,22 +1,28 @@
from __future__ import division
+
+import logging
+import logging.handlers
+
from outputplugin import OutputPlugin
-import logging, logging.handlers
# Dict of flags to gate adding the syslogHandler only once to the given singleton logger
loggerInitialized = {}
+
class SyslogOutOutputPlugin(OutputPlugin):
useOutputQueue = True
name = 'syslogout'
MAXQUEUELENGTH = 10
- validSettings = [ 'syslogDestinationHost', 'syslogDestinationPort' ]
- defaultableSettings = [ 'syslogDestinationHost', 'syslogDestinationPort' ]
- intSettings = [ 'syslogDestinationPort' ]
+ validSettings = ['syslogDestinationHost', 'syslogDestinationPort']
+ defaultableSettings = ['syslogDestinationHost', 'syslogDestinationPort']
+ intSettings = ['syslogDestinationPort']
def __init__(self, sample, output_counter=None):
OutputPlugin.__init__(self, sample, output_counter)
- self._syslogDestinationHost = sample.syslogDestinationHost if hasattr(sample, 'syslogDestinationHost') and sample.syslogDestinationHost else '127.0.0.1'
- self._syslogDestinationPort = sample.syslogDestinationPort if hasattr(sample, 'syslogDestinationPort') and sample.syslogDestinationPort else 1514
+ self._syslogDestinationHost = sample.syslogDestinationHost if hasattr(
+ sample, 'syslogDestinationHost') and sample.syslogDestinationHost else '127.0.0.1'
+ self._syslogDestinationPort = sample.syslogDestinationPort if hasattr(
+ sample, 'syslogDestinationPort') and sample.syslogDestinationPort else 1514
loggerName = 'syslog' + sample.name
self._l = logging.getLogger(loggerName)
@@ -25,8 +31,9 @@ def __init__(self, sample, output_counter=None):
global loggerInitialized
# This class is instantiated at least once each interval. Since each logger with a given name is a singleton,
# only add the syslog handler once instead of every interval.
- if not loggerName in loggerInitialized:
- syslogHandler = logging.handlers.SysLogHandler(address=(self._syslogDestinationHost, int(self._syslogDestinationPort)))
+ if loggerName not in loggerInitialized:
+ syslogHandler = logging.handlers.SysLogHandler(
+ address=(self._syslogDestinationHost, int(self._syslogDestinationPort)))
self._l.addHandler(syslogHandler)
loggerInitialized[loggerName] = True
@@ -34,6 +41,7 @@ def flush(self, q):
for x in q:
self._l.info(x['_raw'].rstrip())
+
def load():
"""Returns an instance of the plugin"""
return SyslogOutOutputPlugin
diff --git a/splunk_eventgen/lib/plugins/output/tcpout.py b/splunk_eventgen/lib/plugins/output/tcpout.py
index 3432d4bd..4658a00f 100644
--- a/splunk_eventgen/lib/plugins/output/tcpout.py
+++ b/splunk_eventgen/lib/plugins/output/tcpout.py
@@ -1,7 +1,10 @@
from __future__ import division
-from outputplugin import OutputPlugin
+
import logging
+from outputplugin import OutputPlugin
+
+
class TcpOutputPlugin(OutputPlugin):
useOutputQueue = False
name = 'tcpout'
@@ -10,13 +13,14 @@ class TcpOutputPlugin(OutputPlugin):
def __init__(self, sample, output_counter=None):
OutputPlugin.__init__(self, sample, output_counter)
- self._tcpDestinationHost = sample.tcpDestinationHost if hasattr(sample,'tcpDestinationHost') and sample.tcpDestinationHost else '127.0.0.1'
- self._tcpDestinationPort = sample.tcpDestinationPort if hasattr(sample,'tcpDestinationPort') and sample.tcpDestinationPort else '3333'
+ self._tcpDestinationHost = sample.tcpDestinationHost if hasattr(
+ sample, 'tcpDestinationHost') and sample.tcpDestinationHost else '127.0.0.1'
+ self._tcpDestinationPort = sample.tcpDestinationPort if hasattr(
+ sample, 'tcpDestinationPort') and sample.tcpDestinationPort else '3333'
import socket # Import socket module
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- # Bind to the port
def flush(self, q):
self.s.connect((self._tcpDestinationHost, int(self._tcpDestinationPort)))
self.logger.info("Socket connected to {0}:{1}".format(self._tcpDestinationHost, self._tcpDestinationPort))
@@ -27,6 +31,7 @@ def flush(self, q):
def _setup_logging(self):
self.logger = logging.getLogger('eventgen')
+
def load():
"""Returns an instance of the plugin"""
- return TcpOutputPlugin
\ No newline at end of file
+ return TcpOutputPlugin
diff --git a/splunk_eventgen/lib/plugins/output/udpout.py b/splunk_eventgen/lib/plugins/output/udpout.py
index 43477d0f..30e74324 100644
--- a/splunk_eventgen/lib/plugins/output/udpout.py
+++ b/splunk_eventgen/lib/plugins/output/udpout.py
@@ -1,7 +1,10 @@
from __future__ import division
-from outputplugin import OutputPlugin
+
import logging
+from outputplugin import OutputPlugin
+
+
class UdpOutputPlugin(OutputPlugin):
useOutputQueue = False
name = 'udpout'
@@ -10,8 +13,10 @@ class UdpOutputPlugin(OutputPlugin):
def __init__(self, sample, output_counter=None):
OutputPlugin.__init__(self, sample, output_counter)
- self._udpDestinationHost = sample.udpDestinationHost if hasattr(sample,'udpDestinationHost') and sample.udpDestinationHost else '127.0.0.1'
- self._udpDestinationPort = sample.udpDestinationPort if hasattr(sample,'udpDestinationPort') and sample.udpDestinationPort else '3333'
+ self._udpDestinationHost = sample.udpDestinationHost if hasattr(
+ sample, 'udpDestinationHost') and sample.udpDestinationHost else '127.0.0.1'
+ self._udpDestinationPort = sample.udpDestinationPort if hasattr(
+ sample, 'udpDestinationPort') and sample.udpDestinationPort else '3333'
import socket # Import socket module
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
@@ -25,6 +30,7 @@ def flush(self, q):
def _setup_logging(self):
self.logger = logging.getLogger('eventgen')
+
def load():
"""Returns an instance of the plugin"""
- return UdpOutputPlugin
\ No newline at end of file
+ return UdpOutputPlugin
diff --git a/splunk_eventgen/lib/plugins/rater/config.py b/splunk_eventgen/lib/plugins/rater/config.py
index d15136bd..d49581de 100644
--- a/splunk_eventgen/lib/plugins/rater/config.py
+++ b/splunk_eventgen/lib/plugins/rater/config.py
@@ -1,7 +1,8 @@
from __future__ import division
+
+import datetime
import logging
import logging.handlers
-import datetime
import random
import os
@@ -21,7 +22,7 @@ def __init__(self, sample):
def __str__(self):
"""Only used for debugging, outputs a pretty printed representation of this output"""
# Eliminate recursive going back to parent
- temp = dict([ (key, value) for (key, value) in self.__dict__.items() if key != '_c'])
+ # temp = dict([(key, value) for (key, value) in self.__dict__.items() if key != '_c'])
# return pprint.pformat(temp)
return ""
@@ -50,21 +51,21 @@ def rate(self):
self.logger.error('No sample found for default generator, cannot generate events')
self._sample.count = len(self._sample.sampleDict)
self._generatorWorkers = int(self._generatorWorkers)
- count = self._sample.count/self._generatorWorkers
+ count = self._sample.count / self._generatorWorkers
# 5/8/12 CS We've requested not the whole file, so we should adjust count based on
# hourOfDay, dayOfWeek and randomizeCount configs
rateFactor = 1.0
if self._sample.randomizeCount:
try:
- self.logger.debug("randomizeCount for sample '%s' in app '%s' is %s"
- % (self._sample.name, self._sample.app, self._sample.randomizeCount))
+ self.logger.debug("randomizeCount for sample '%s' in app '%s' is %s" %
+ (self._sample.name, self._sample.app, self._sample.randomizeCount))
# If we say we're going to be 20% variable, then that means we
# can be .1% high or .1% low. Math below does that.
randBound = round(self._sample.randomizeCount * 1000, 0)
rand = random.randint(0, randBound)
- randFactor = 1+((-((randBound / 2) - rand)) / 1000)
- self.logger.debug("randFactor for sample '%s' in app '%s' is %s" \
- % (self._sample.name, self._sample.app, randFactor))
+ randFactor = 1 + ((-((randBound / 2) - rand)) / 1000)
+ self.logger.debug(
+ "randFactor for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, randFactor))
rateFactor *= randFactor
except:
import traceback
@@ -73,12 +74,14 @@ def rate(self):
if type(self._sample.hourOfDayRate) == dict:
try:
rate = self._sample.hourOfDayRate[str(self._sample.now().hour)]
- self.logger.debug("hourOfDayRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
+ self.logger.debug(
+ "hourOfDayRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
rateFactor *= rate
except KeyError:
import traceback
stack = traceback.format_exc()
- self.logger.error("Hour of day rate failed for sample '%s'. Stacktrace %s" % (self._sample.name, stack))
+ self.logger.error(
+ "Hour of day rate failed for sample '%s'. Stacktrace %s" % (self._sample.name, stack))
if type(self._sample.dayOfWeekRate) == dict:
try:
weekday = datetime.date.weekday(self._sample.now())
@@ -87,43 +90,52 @@ def rate(self):
else:
weekday += 1
rate = self._sample.dayOfWeekRate[str(weekday)]
- self.logger.debugv("dayOfWeekRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
+ self.logger.debug(
+ "dayOfWeekRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
rateFactor *= rate
except KeyError:
import traceback
- stack = traceback.format_exc()
- self.logger.error("Hour of day rate failed for sample '%s'. Stacktrace %s" % (self._sample.name, stack))
+ stack = traceback.format_exc()
+ self.logger.error(
+ "Hour of day rate failed for sample '%s'. Stacktrace %s" % (self._sample.name, stack))
if type(self._sample.minuteOfHourRate) == dict:
try:
rate = self._sample.minuteOfHourRate[str(self._sample.now().minute)]
- self.logger.debugv("minuteOfHourRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
+ self.logger.debug(
+ "minuteOfHourRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
rateFactor *= rate
except KeyError:
import traceback
- stack = traceback.format_exc()
- self.logger.error("Minute of hour rate failed for sample '%s'. Stacktrace %s" % (self._sample.name, stack))
+ stack = traceback.format_exc()
+ self.logger.error(
+ "Minute of hour rate failed for sample '%s'. Stacktrace %s" % (self._sample.name, stack))
if type(self._sample.dayOfMonthRate) == dict:
try:
rate = self._sample.dayOfMonthRate[str(self._sample.now().day)]
- self.logger.debugv("dayOfMonthRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
+ self.logger.debug(
+ "dayOfMonthRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
rateFactor *= rate
except KeyError:
import traceback
- stack = traceback.format_exc()
- self.logger.error("Day of Month rate for sample '%s' failed. Stacktrace %s" % (self._sample.name, stack))
+ stack = traceback.format_exc()
+ self.logger.error(
+ "Day of Month rate for sample '%s' failed. Stacktrace %s" % (self._sample.name, stack))
if type(self._sample.monthOfYearRate) == dict:
try:
rate = self._sample.monthOfYearRate[str(self._sample.now().month)]
- self.logger.debugv("monthOfYearRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
+ self.logger.debug(
+ "monthOfYearRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
rateFactor *= rate
except KeyError:
import traceback
- stack = traceback.format_exc()
- self.logger.error("Month Of Year rate failed for sample '%s'. Stacktrace %s" % (self._sample.name, stack))
+ stack = traceback.format_exc()
+ self.logger.error(
+ "Month Of Year rate failed for sample '%s'. Stacktrace %s" % (self._sample.name, stack))
ret = int(round(count * rateFactor, 0))
if rateFactor != 1.0:
self.logger.debug("Original count: %s Rated count: %s Rate factor: %s" % (count, ret, rateFactor))
return ret
+
def load():
return ConfigRater
diff --git a/splunk_eventgen/lib/plugins/rater/perdayvolume.py b/splunk_eventgen/lib/plugins/rater/perdayvolume.py
index cfdf8746..3c8d217f 100644
--- a/splunk_eventgen/lib/plugins/rater/perdayvolume.py
+++ b/splunk_eventgen/lib/plugins/rater/perdayvolume.py
@@ -1,7 +1,8 @@
from __future__ import division
-from config import ConfigRater
+
import datetime
import random
+from config import ConfigRater
class PerDayVolume(ConfigRater):
@@ -16,7 +17,7 @@ def __init__(self, sample):
self._generatorWorkers = self._sample.config.generatorWorkers
def rate(self):
- perdayvolume = float(self._sample.perDayVolume)/self._generatorWorkers
+ perdayvolume = float(self._sample.perDayVolume) / self._generatorWorkers
# Convert perdayvolume to bytes from GB
perdayvolume = perdayvolume * 1024 * 1024 * 1024
interval = self._sample.interval
@@ -28,21 +29,20 @@ def rate(self):
perintervalvolume = (perdayvolume / intervalsperday)
count = self._sample.count
-
# 5/8/12 CS We've requested not the whole file, so we should adjust count based on
# hourOfDay, dayOfWeek and randomizeCount configs
rateFactor = 1.0
- if self._sample.randomizeCount != 0 and self._sample.randomizeCount != None:
+ if self._sample.randomizeCount != 0 and self._sample.randomizeCount is not None:
try:
- self.logger.debugv("randomizeCount for sample '%s' in app '%s' is %s" \
- % (self._sample.name, self._sample.app, self._sample.randomizeCount))
+ self.logger.debugv("randomizeCount for sample '%s' in app '%s' is %s" %
+ (self._sample.name, self._sample.app, self._sample.randomizeCount))
# If we say we're going to be 20% variable, then that means we
# can be .1% high or .1% low. Math below does that.
randBound = round(self._sample.randomizeCount * 1000, 0)
rand = random.randint(0, randBound)
- randFactor = 1+((-((randBound / 2) - rand)) / 1000)
- self.logger.debug("randFactor for sample '%s' in app '%s' is %s" \
- % (self._sample.name, self._sample.app, randFactor))
+ randFactor = 1 + ((-((randBound / 2) - rand)) / 1000)
+ self.logger.debug(
+ "randFactor for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, randFactor))
rateFactor *= randFactor
except:
import traceback
@@ -51,12 +51,14 @@ def rate(self):
if type(self._sample.hourOfDayRate) == dict:
try:
rate = self._sample.hourOfDayRate[str(self._sample.now().hour)]
- self.logger.debugv("hourOfDayRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
+ self.logger.debugv(
+ "hourOfDayRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
rateFactor *= rate
except KeyError:
import traceback
stack = traceback.format_exc()
- self.logger.error("Hour of day rate failed for sample '%s'. Stacktrace %s" % (self._sample.name, stack))
+ self.logger.error(
+ "Hour of day rate failed for sample '%s'. Stacktrace %s" % (self._sample.name, stack))
if type(self._sample.dayOfWeekRate) == dict:
try:
weekday = datetime.date.weekday(self._sample.now())
@@ -65,46 +67,55 @@ def rate(self):
else:
weekday += 1
rate = self._sample.dayOfWeekRate[str(weekday)]
- self.logger.debugv("dayOfWeekRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
+ self.logger.debugv(
+ "dayOfWeekRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
rateFactor *= rate
except KeyError:
import traceback
stack = traceback.format_exc()
- self.logger.error("Hour of day rate failed for sample '%s'. Stacktrace %s" % (self._sample.name, stack))
+ self.logger.error(
+ "Hour of day rate failed for sample '%s'. Stacktrace %s" % (self._sample.name, stack))
if type(self._sample.minuteOfHourRate) == dict:
try:
rate = self._sample.minuteOfHourRate[str(self._sample.now().minute)]
- self.logger.debugv("minuteOfHourRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
+ self.logger.debugv(
+ "minuteOfHourRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
rateFactor *= rate
except KeyError:
import traceback
stack = traceback.format_exc()
- self.logger.error("Minute of hour rate failed for sample '%s'. Stacktrace %s" % (self._sample.name, stack))
+ self.logger.error(
+ "Minute of hour rate failed for sample '%s'. Stacktrace %s" % (self._sample.name, stack))
if type(self._sample.dayOfMonthRate) == dict:
try:
rate = self._sample.dayOfMonthRate[str(self._sample.now().day)]
- self.logger.debugv("dayOfMonthRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
+ self.logger.debugv(
+ "dayOfMonthRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
rateFactor *= rate
except KeyError:
import traceback
stack = traceback.format_exc()
- self.logger.error("Day of Month rate for sample '%s' failed. Stacktrace %s" % (self._sample.name, stack))
+ self.logger.error(
+ "Day of Month rate for sample '%s' failed. Stacktrace %s" % (self._sample.name, stack))
if type(self._sample.monthOfYearRate) == dict:
try:
rate = self._sample.monthOfYearRate[str(self._sample.now().month)]
- self.logger.debugv("monthOfYearRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
+ self.logger.debugv(
+ "monthOfYearRate for sample '%s' in app '%s' is %s" % (self._sample.name, self._sample.app, rate))
rateFactor *= rate
except KeyError:
import traceback
stack = traceback.format_exc()
- self.logger.error("Month Of Year rate failed for sample '%s'. Stacktrace %s" % (self._sample.name, stack))
+ self.logger.error(
+ "Month Of Year rate failed for sample '%s'. Stacktrace %s" % (self._sample.name, stack))
self.logger.debug("Size per interval: %s, rate factor to adjust by: %s" % (perintervalvolume, rateFactor))
ret = int(round(perintervalvolume * rateFactor, 0))
if rateFactor != 1.0:
self.logger.debug("Original count: %s Rated count: %s Rate factor: %s" % (count, ret, rateFactor))
- self.logger.debug("Finished rating, interval: {0}s, generation rate: {1} MB/interval".format(interval, round((ret / 1024 / 1024), 4)))
+ self.logger.debug("Finished rating, interval: {0}s, generation rate: {1} MB/interval".format(
+ interval, round((ret / 1024 / 1024), 4)))
return ret
def load():
- return PerDayVolume
\ No newline at end of file
+ return PerDayVolume
diff --git a/splunk_eventgen/lib/timeparser.py b/splunk_eventgen/lib/timeparser.py
index 4efeab36..020818b8 100644
--- a/splunk_eventgen/lib/timeparser.py
+++ b/splunk_eventgen/lib/timeparser.py
@@ -1,86 +1,89 @@
import datetime
-import re
-import math
import logging
-
+import math
+import os
+import re
# Hack to allow distributing python modules since Splunk doesn't have setuptools
# We create the egg outside of Splunk (with a copy of python2.7 and using Python only modules
# To avoid being platform specific) and then append the egg path and import the module
# If we get a lot of these we'll move the eggs from bin to lib
#
# python-dateutil acquired from http://labix.org/python-dateutil. BSD Licensed
-import sys, os
+import sys
+
path_prepend = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'lib')
sys.path.append(path_prepend + '/python_dateutil-1.4.1-py2.7.egg')
-import dateutil.parser as dateutil_parser
+import dateutil.parser as dateutil_parser # noqa isort:skip
# If we're inside eventgen, we'll have a global logger, if not set one up
logging.getLogger('eventgen')
+
# 5-5-2012 CS Replacing TimeParser with our own code to remove Splunk dependency
-# Based off spec for relative time identifiers at http://docs.splunk.com/Documentation/Splunk/latest/SearchReference/SearchTimeModifiers#How_to_specify_relative_time_modifiers
+# Based off spec for relative time identifiers at http://docs.splunk.com/Documentation/Splunk/latest/SearchReference/SearchTimeModifiers#How_to_specify_relative_time_modifiers # noqa
# If we're not relative, we'll try to parse it as an ISO compliant time
def timeParser(ts='now', timezone=datetime.timedelta(days=1), now=None, utcnow=None):
if ts == 'now':
if timezone.days > 0:
- if now == None:
+ if now is None:
return datetime.datetime.now()
else:
return now()
else:
- if utcnow == None:
+ if utcnow is None:
return datetime.datetime.now()
else:
return utcnow() + timezone
else:
if ts[:1] == '+' or ts[:1] == '-':
if timezone.days > 0:
- if now == None:
+ if now is None:
ret = datetime.datetime.now()
else:
ret = now()
else:
- if utcnow == None:
+ if utcnow is None:
ret = datetime.datetime.utcnow() + timezone
else:
ret = utcnow() + timezone
-
- unitsre = "(seconds|second|secs|sec|minutes|minute|min|hours|hour|hrs|hr|days|day|weeks|week|w[0-6]|months|month|mon|quarters|quarter|qtrs|qtr|years|year|yrs|yr|s|h|m|d|w|y|w|q)"
- reltimere = "(?i)(?P[+-]*)(?P\d{1,})(?P"+unitsre+"{1})(([\@](?P"+unitsre+"{1})((?P[+-])(?P\d+)(?P"+unitsre+"{1}))*)*)"
-
+
+ unitsre = "(seconds|second|secs|sec|minutes|minute|min|hours|hour|hrs|hr|days|day|weeks|week|w[0-6]|" + \
+ "months|month|mon|quarters|quarter|qtrs|qtr|years|year|yrs|yr|s|h|m|d|w|y|w|q)"
+ reltimere = "(?i)(?P[+-]*)(?P\d{1,})(?P" + unitsre + "{1})(([\@](?P" + \
+ unitsre + "{1})((?P[+-])(?P\d+)(?P" + unitsre + \
+ "{1}))*)*)"
+
results = re.match(reltimere, ts)
resultsdict = results.groupdict()
-
+
# Handle first part of the time string
- if resultsdict['plusminus'] != None and resultsdict['num'] != None \
- and resultsdict['unit'] != None:
+ if resultsdict['plusminus'] is not None and resultsdict['num'] is not None \
+ and resultsdict['unit'] is not None:
ret = timeParserTimeMath(resultsdict['plusminus'], resultsdict['num'], resultsdict['unit'], ret)
-
+
# Now handle snap-to
- if resultsdict['snapunit'] != None:
+ if resultsdict['snapunit'] is not None:
if resultsdict['snapunit'] in ('s', 'sec', 'secs', 'second', 'seconds'):
- ret = datetime.datetime(ret.year, ret.month, ret.day, ret.hour, \
- ret.minute, ret.second, 0)
+ ret = datetime.datetime(ret.year, ret.month, ret.day, ret.hour, ret.minute, ret.second, 0)
elif resultsdict['snapunit'] in ('m', 'min', 'minute', 'minutes'):
- ret = datetime.datetime(ret.year, ret.month, ret.day, ret.hour, \
- ret.minute, 0, 0)
+ ret = datetime.datetime(ret.year, ret.month, ret.day, ret.hour, ret.minute, 0, 0)
elif resultsdict['snapunit'] in ('h', 'hr', 'hrs', 'hour', 'hours'):
ret = datetime.datetime(ret.year, ret.month, ret.day, ret.hour, 0, 0, 0)
elif resultsdict['snapunit'] in ('d', 'day', 'days'):
ret = datetime.datetime(ret.year, ret.month, ret.day, 0, 0, 0, 0)
- elif re.match('w[0-6]', resultsdict['snapunit']) != None or \
+ elif re.match('w[0-6]', resultsdict['snapunit']) is not None or \
resultsdict['snapunit'] in ('w', 'week', 'weeks'):
if resultsdict['snapunit'] in ('w', 'week', 'weeks'):
resultsdict['snapunit'] = 'w0'
weekdaynum = int(resultsdict['snapunit'][1:2])
-
+
# Convert python's weekdays to Splunk's
retweekday = datetime.date.weekday(ret)
if retweekday == 6:
retweekday = 0
else:
retweekday += 1
-
+
if weekdaynum <= retweekday:
ret = ret + datetime.timedelta(days=(weekdaynum - retweekday))
ret = datetime.datetime(ret.year, ret.month, ret.day, 0, 0, 0, 0)
@@ -96,23 +99,24 @@ def timeParser(ts='now', timezone=datetime.timedelta(days=1), now=None, utcnow=N
ret = datetime.datetime(ret.year, int(math.floor(ret.month / 3.3 + 1) * 3), 1, 0, 0, 0, 0)
elif resultsdict['snapunit'] in ('y', 'yr', 'yrs', 'year', 'years'):
ret = datetime.datetime(ret.year, 1, 1, 0, 0, 0, 0)
-
- if resultsdict['snapplusminus'] != None and resultsdict['snaprelnum'] != None \
- and resultsdict['snaprelunit'] != None:
- ret = timeParserTimeMath(resultsdict['snapplusminus'], resultsdict['snaprelnum'],
- resultsdict['snaprelunit'], ret)
+
+ if resultsdict['snapplusminus'] is not None and resultsdict['snaprelnum'] is not None \
+ and resultsdict['snaprelunit'] is not None:
+ ret = timeParserTimeMath(resultsdict['snapplusminus'], resultsdict['snaprelnum'],
+ resultsdict['snaprelunit'], ret)
return ret
-
+
else:
- raise ValueError('Cannot parse relative time string for %s' %(ts))
+ raise ValueError('Cannot parse relative time string for %s' % (ts))
else:
- # The spec says we must be a ISO8601 time. This parser should be able to handle
+ # The spec says we must be a ISO8601 time. This parser should be able to handle
# more date formats though, so we can be liberal in what we accept
return dateutil_parser.parse(ts)
- #except ValueError:
+ # except ValueError:
# raise ValueError("Cannot parse date/time for %s" % (ts))
+
def timeParserTimeMath(plusminus, num, unit, ret):
try:
num = int(num)
@@ -126,59 +130,59 @@ def timeParserTimeMath(plusminus, num, unit, ret):
elif unit in ('d', 'day', 'days'):
td = datetime.timedelta(days=int(num))
elif unit in ('w', 'week', 'weeks'):
- td = datetime.timedelta(days=(int(num)*7))
- elif re.match('w[0-6]', unit) != None:
- logger.error('Day of week is only available in snap-to. Time string: %s' % (ts))
+ td = datetime.timedelta(days=(int(num) * 7))
+ elif re.match('w[0-6]', unit) is not None:
+ logging.error('Day of week is only available in snap-to. Time string: %s' % td)
return False
# Normalize out all year/quarter/months to months and do the math on that
- elif unit in ('mon', 'month', 'months') or \
- unit in ('q', 'qtr', 'qtrs', 'quarter', 'quarters') or \
- unit in ('y', 'yr', 'yrs', 'year', 'years'):
+ elif unit in ('mon', 'month', 'months') or unit in ('q', 'qtr', 'qtrs', 'quarter', 'quarters') or \
+ unit in ('y', 'yr', 'yrs', 'year', 'years'):
if unit in ('q', 'qtr', 'qtrs', 'quarter', 'quarters'):
num *= 3
elif unit in ('y', 'yr', 'yrs', 'year', 'years'):
num *= 12
-
+
monthnum = int(num) * -1 if plusminus == '-' else int(num)
if abs(monthnum) / 12 > 0:
- yearnum = int(math.floor(abs(monthnum)/12) * -1 if plusminus == '-' else int(math.floor(abs(monthnum)/12)))
- monthnum = int((abs(monthnum) % 12) * -1 if plusminus == '-' else int((abs(monthnum)%12)))
- ret = datetime.datetime(ret.year + yearnum, ret.month + monthnum, ret.day, ret.hour,
- ret.minute, ret.second, ret.microsecond)
+ yearnum = int(
+ math.floor(abs(monthnum) / 12) * -1 if plusminus == '-' else int(math.floor(abs(monthnum) / 12)))
+ monthnum = int((abs(monthnum) % 12) * -1 if plusminus == '-' else int((abs(monthnum) % 12)))
+ ret = datetime.datetime(ret.year + yearnum, ret.month + monthnum, ret.day, ret.hour, ret.minute,
+ ret.second, ret.microsecond)
elif monthnum > 0:
if ret.month + monthnum > 12:
- ret = datetime.datetime(ret.year+1, ((ret.month+monthnum)%12),
- ret.day, ret.hour, ret.minute, ret.second, ret.microsecond)
+ ret = datetime.datetime(ret.year + 1, ((ret.month + monthnum) % 12), ret.day, ret.hour, ret.minute,
+ ret.second, ret.microsecond)
else:
- ret = datetime.datetime(ret.year, ret.month+monthnum, ret.day,
- ret.hour, ret.minute, ret.second, ret.microsecond)
+ ret = datetime.datetime(ret.year, ret.month + monthnum, ret.day, ret.hour, ret.minute, ret.second,
+ ret.microsecond)
elif monthnum <= 0:
if ret.month + monthnum <= 0:
- ret = datetime.datetime(ret.year-1, (12-abs(ret.month+monthnum)),
- ret.day, ret.hour, ret.minute, ret.second, ret.microsecond)
+ ret = datetime.datetime(ret.year - 1, (12 - abs(ret.month + monthnum)), ret.day, ret.hour,
+ ret.minute, ret.second, ret.microsecond)
else:
- ret = datetime.datetime(ret.year, ret.month+monthnum, ret.day,
- ret.hour, ret.minute, ret.second, ret.microsecond)
+ ret = datetime.datetime(ret.year, ret.month + monthnum, ret.day, ret.hour, ret.minute, ret.second,
+ ret.microsecond)
except ValueError:
- logger.error('Cannot parse relative time string')
+ logging.error('Cannot parse relative time string')
import traceback
- stack = traceback.format_exc()
- logger.debug('%s', stack)
+ stack = traceback.format_exc()
+ logging.debug('%s', stack)
return False
-
- if td != None:
+
+ if td is not None:
if plusminus == '-':
td = td * -1
ret = ret + td
-
+
# Always chop microseconds to maintain compatibility with Splunk's parser
ret = datetime.datetime(ret.year, ret.month, ret.day, ret.hour, ret.minute, ret.second)
-
+
return ret
-
-## Converts Time Delta object to number of seconds in delta
+
+
+# Converts Time Delta object to number of seconds in delta
def timeDelta2secs(timeDiff):
deltaSecs = (timeDiff.microseconds + (timeDiff.seconds + timeDiff.days * 24 * 3600) * 10**6) / 10**6
return int(deltaSecs)
-
\ No newline at end of file
diff --git a/splunk_eventgen/logger/logger_config.py b/splunk_eventgen/logger/logger_config.py
index d2d5b46f..444ef5f9 100644
--- a/splunk_eventgen/logger/logger_config.py
+++ b/splunk_eventgen/logger/logger_config.py
@@ -2,26 +2,15 @@
'version': 1,
'formatters': {
'detailed': {
- 'class': 'logging.Formatter',
- 'format': '%(asctime)s %(name)-15s %(levelname)-8s %(processName)-10s %(message)s'
- }
- },
+ 'class': 'logging.Formatter', 'format':
+ '%(asctime)s %(name)-15s %(levelname)-8s %(processName)-10s %(message)s'}},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'level': 'INFO',
- 'formatter': 'detailed',
- },
- 'main': {
- 'class': 'logging.FileHandler',
- 'filename': 'eventgen-controller-main.log',
- 'mode': 'w',
- 'formatter': 'detailed',
- }
- },
- 'root': {
- 'level': 'DEBUG',
- 'handlers': ['console', 'main']
- },
-}
-
+ 'formatter': 'detailed', }, 'main': {
+ 'class': 'logging.FileHandler',
+ 'filename': 'eventgen-controller-main.log',
+ 'mode': 'w',
+ 'formatter': 'detailed', }},
+ 'root': {'level': 'DEBUG', 'handlers': ['console', 'main']}, }
diff --git a/splunk_eventgen/logger/requests_futures/__init__.py b/splunk_eventgen/logger/requests_futures/__init__.py
index 9ac9cd31..ac0c4f3e 100755
--- a/splunk_eventgen/logger/requests_futures/__init__.py
+++ b/splunk_eventgen/logger/requests_futures/__init__.py
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
# Requests Futures
-
"""
async requests HTTP library
~~~~~~~~~~~~~~~~~~~~~
@@ -22,8 +21,10 @@
try: # Python 2.7+
from logging import NullHandler
except ImportError:
+
class NullHandler(logging.Handler):
def emit(self, record):
pass
+
logging.getLogger(__name__).addHandler(NullHandler())
diff --git a/splunk_eventgen/logger/requests_futures/sessions.py b/splunk_eventgen/logger/requests_futures/sessions.py
index 7fba4226..643f4e1d 100755
--- a/splunk_eventgen/logger/requests_futures/sessions.py
+++ b/splunk_eventgen/logger/requests_futures/sessions.py
@@ -19,9 +19,9 @@
print(response.content)
"""
-from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
+from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
from functools import partial
-from pickle import dumps, PickleError
+from pickle import PickleError, dumps
from requests import Session
from requests.adapters import DEFAULT_POOLSIZE, HTTPAdapter
@@ -38,9 +38,7 @@ def wrap(self, sup, background_callback, *args_, **kwargs_):
class FuturesSession(Session):
-
- def __init__(self, executor=None, max_workers=2, session=None, *args,
- **kwargs):
+ def __init__(self, executor=None, max_workers=2, session=None, *args, **kwargs):
"""Creates a FuturesSession
Notes
@@ -56,8 +54,7 @@ def __init__(self, executor=None, max_workers=2, session=None, *args,
executor = ThreadPoolExecutor(max_workers=max_workers)
# set connection pool size equal to max_workers if needed
if max_workers > DEFAULT_POOLSIZE:
- adapter_kwargs = dict(pool_connections=max_workers,
- pool_maxsize=max_workers)
+ adapter_kwargs = dict(pool_connections=max_workers, pool_maxsize=max_workers)
self.mount('https://', HTTPAdapter(**adapter_kwargs))
self.mount('http://', HTTPAdapter(**adapter_kwargs))
diff --git a/splunk_eventgen/splunk_app/bin/modinput_eventgen.py b/splunk_eventgen/splunk_app/bin/modinput_eventgen.py
index db1e6115..15463bc5 100644
--- a/splunk_eventgen/splunk_app/bin/modinput_eventgen.py
+++ b/splunk_eventgen/splunk_app/bin/modinput_eventgen.py
@@ -1,25 +1,26 @@
#!/usr/bin/env python
# encoding: utf-8
-import sys
-import logging
import argparse
+import logging
import signal
+import sys
+from modinput import ModularInput
+from modinput.fields import VerbosityField
# Set path so libraries will load
from splunk.clilib.bundle_paths import make_splunkhome_path
-sys.path.insert(0, make_splunkhome_path(['etc', 'apps', 'SA-Eventgen', 'lib']))
-sys.path.insert(0, make_splunkhome_path(['etc', 'apps', 'SA-Eventgen', 'lib', 'splunk_eventgen', 'lib']))
-
-from modinput.fields import BooleanField, Field, VerbosityField
-from xmloutput import setupLogger, XMLOutputManager
-from modinput import ModularInput
from splunk_eventgen import eventgen_core
from splunk_eventgen.lib import eventgenconfig
+from xmloutput import XMLOutputManager, setupLogger
+
+sys.path.insert(0, make_splunkhome_path(['etc', 'apps', 'SA-Eventgen', 'lib']))
+sys.path.insert(0, make_splunkhome_path(['etc', 'apps', 'SA-Eventgen', 'lib', 'splunk_eventgen', 'lib']))
# Initialize logging
logger = setupLogger(logger=None, log_format='%(asctime)s %(levelname)s [Eventgen] %(message)s', level=logging.DEBUG,
log_name="modinput_eventgen.log", logger_name="eventgen_app")
+
class SimpleNamespace(dict):
"""dot.notation access to dictionary attributes"""
__getattr__ = dict.get
@@ -29,12 +30,8 @@ class SimpleNamespace(dict):
class Eventgen(ModularInput):
scheme_args = {
- 'title': "SA-Eventgen",
- 'description': "This modular input generates data for Splunk.",
- 'use_external_validation': "true",
- 'streaming_mode': "xml",
- 'use_single_instance': "False"
- }
+ 'title': "SA-Eventgen", 'description': "This modular input generates data for Splunk.",
+ 'use_external_validation': "true", 'streaming_mode': "xml", 'use_single_instance': "False"}
def __init__(self):
logger.debug("Setting up SA-Eventgen Modular Input")
@@ -42,9 +39,8 @@ def __init__(self):
self.args = [
VerbosityField("verbosity", "Verbosity",
- "Logging Level (DEBUG(10), INFO(20), WARN(30), ERROR(40), CRITICAL(50))",
- required_on_create=True, required_on_edit=True)
- ]
+ "Logging Level (DEBUG(10), INFO(20), WARN(30), ERROR(40), CRITICAL(50))",
+ required_on_create=True, required_on_edit=True)]
ModularInput.__init__(self, self.scheme_args, self.args)
def create_args(self):
@@ -138,14 +134,17 @@ def run(self, stanza, input_config, **kwargs):
logger.error("Main code exit, Exception caught: %s" % e)
raise e
+
def handler(signum, frame):
logger.info("Eventgen Modinput takes signal {0}. Exiting".format(signum))
sys.exit(0)
+
def handle_signal():
if not sys.platform.startswith('win') and sys.platform != "cygwin":
signal.signal(signal.SIGPIPE, handler)
+
if __name__ == '__main__':
handle_signal()
worker = Eventgen()
diff --git a/splunk_eventgen/splunk_app/lib/modinput/__init__.py b/splunk_eventgen/splunk_app/lib/modinput/__init__.py
index 11542901..44c4bcc3 100644
--- a/splunk_eventgen/splunk_app/lib/modinput/__init__.py
+++ b/splunk_eventgen/splunk_app/lib/modinput/__init__.py
@@ -10,14 +10,18 @@
import sys
import time
import xml.dom
-from xml.dom.minidom import Document
import xml.sax.saxutils
+from xml.dom.minidom import Document
import splunk
import splunk.clilib
import splunk.version
-from splunk.models.app import App
from splunk.clilib.bundle_paths import get_slaveapps_base_path
+from splunk.models.app import App
+from xmloutput import setupLogger
+
+from .fields import (BooleanField, Field, FieldValidationException, IntervalField)
+
try:
from splunk.clilib.bundle_paths import make_splunkhome_path
except ImportError:
@@ -28,27 +32,13 @@
else:
sys.path.append(make_splunkhome_path(["etc", "apps", "@appname@", "lib"]))
-from .fields import BooleanField
-from .fields import DurationField
-from .fields import Field
-from .fields import FieldValidationException
-from .fields import FloatField
-from .fields import IntegerField
-from .fields import IntervalField
-from .fields import ListField
-from .fields import RangeField
-from .fields import RegexField
-from .fields import SeverityField
-
-from xmloutput import setupLogger, XMLOutputManager
-
# Define logger using the name of the script here, versus in the modular_input class.
-#logger = log.setup_logger(name='python_modular_input', level=logging.INFO)
-logger = setupLogger(logger=None, log_format='%(asctime)s %(levelname)s [ModularInput] %(message)s', level=logging.INFO, log_name="python_modular_input.log", logger_name="modinput")
+# logger = log.setup_logger(name='python_modular_input', level=logging.INFO)
+logger = setupLogger(logger=None, log_format='%(asctime)s %(levelname)s [ModularInput] %(message)s', level=logging.INFO,
+ log_name="python_modular_input.log", logger_name="modinput")
class ModularInputConfig(object):
-
def __init__(self, server_host, server_uri, session_key, checkpoint_dir, configuration):
self.server_host = server_host
self.server_uri = server_uri
@@ -135,14 +125,13 @@ class ModularInput(object):
# These arguments cover the standard fields that are always supplied
standard_args = [
- BooleanField("disabled", "Disabled", "Whether the modular input is disabled or not"),
- Field("host", "Host", "The host that is running the input"),
- Field("index", "Index", "The index that data should be sent to"),
- IntervalField("interval", "Interval", "The interval the script will be run on"),
- Field("name", "Stanza name", "The name of the stanza for this modular input"),
- Field("source", "Source", "The source for events created by this modular input"),
- Field("sourcetype", "Stanza name", "The name of the stanza for this modular input")
- ]
+ BooleanField("disabled", "Disabled", "Whether the modular input is disabled or not"),
+ Field("host", "Host", "The host that is running the input"),
+ Field("index", "Index", "The index that data should be sent to"),
+ IntervalField("interval", "Interval", "The interval the script will be run on"),
+ Field("name", "Stanza name", "The name of the stanza for this modular input"),
+ Field("source", "Source", "The source for events created by this modular input"),
+ Field("sourcetype", "Stanza name", "The name of the stanza for this modular input")]
checkpoint_dir = None
@@ -401,7 +390,8 @@ def add_xml_args(self, doc, element_args):
def do_validation(self, in_stream=sys.stdin):
"""
- Get the validation data from standard input and attempt to validate it. Returns true if the arguments validated, false otherwise.
+ Get the validation data from standard input and attempt to validate it. Returns true if the arguments validated,
+ false otherwise.
Arguments:
in_stream -- The stream to get the input from (defaults to standard input)
@@ -421,7 +411,7 @@ def validate(self, arguments):
Validate the argument dictionary where each key is a stanza.
Arguments:
- arguments -- The arguments as an dictionary where the key is the stanza and the value is a dictionary of the values.
+ arguments -- a dictionary where the key is the stanza and the value is a dictionary of the values.
"""
# Check each stanza
@@ -541,23 +531,19 @@ def needs_another_run(cls, checkpoint_dir, stanza, interval, cur_time=None):
try:
last_ran = cls.last_ran(checkpoint_dir, stanza)
-
return cls.is_expired(last_ran, interval, cur_time)
-
- except IOError as e:
+ except IOError:
# The file likely doesn't exist
logger.exception("The checkpoint file likely doesn't exist")
return True
- except ValueError as e:
+ except ValueError:
# The file could not be loaded
logger.exception("The checkpoint file could not be loaded")
return True
except Exception as e:
- #Catch all that enforces an extra run
+ # Catch all that enforces an extra run
logger.exception("Unexpected exception caught, enforcing extra run, exception info: " + str(e))
return True
- # Default return value
- return True
@classmethod
def time_to_next_run(cls, checkpoint_dir, stanza, duration):
@@ -582,18 +568,17 @@ def time_to_next_run(cls, checkpoint_dir, stanza, duration):
return time_to_next
except IOError:
# The file likely doesn't exist
- logger.warning("Could not read checkpoint file for last time run, likely does not exist, if this persists debug input immediately")
+ logger.warning("Could not read checkpoint file for last time run, likely does not exist, if this" +
+ "persists debug input immediately")
return 1
except ValueError:
# The file could not be loaded
- logger.exception("Could not read checkpoint file for last time run, if this persists debug input immediately")
+ logger.exception(
+ "Could not read checkpoint file for last time run, if this persists debug input immediately")
return 1
except Exception as e:
logger.exception("Unexpected exception caught, enforcing extra run, exception info: " + str(e))
return 1
- # Default return value
- logger.info("This really should be impossible, but whatevs if your input is breaking check the duration calculations")
- return 1
@classmethod
def save_checkpoint(cls, checkpoint_dir, stanza, last_run):
@@ -663,7 +648,9 @@ def delete_checkpoint_data(self, filename, checkpoint_dir=None):
os.unlink(os.path.join(checkpoint_dir, filename))
return True
except IOError:
- logger.exception('msg="IOError exception when deleting checkpoint data" checkpoint_dir="{}" filename="{}"'.format(checkpoint_dir, filename))
+ logger.exception(
+ 'msg="IOError exception when deleting checkpoint data" checkpoint_dir="{}" filename="{}"'.format(
+ checkpoint_dir, filename))
return False
def set_checkpoint_data(self, filename, data, checkpoint_dir=None):
@@ -693,11 +680,17 @@ def set_checkpoint_data(self, filename, data, checkpoint_dir=None):
json.dump(data, fp)
success = True
except IOError:
- logger.exception('msg="IOError exception when saving checkpoint data" checkpoint_dir="{}" filename="{}"'.format(checkpoint_dir, filename))
+ logger.exception(
+ 'msg="IOError exception when saving checkpoint data" checkpoint_dir="{}" filename="{}"'.format(
+ checkpoint_dir, filename))
except ValueError:
- logger.exception('msg="ValueError when saving checkpoint data (perhaps invalid JSON)" checkpoint_dir="{}" filename="{}"'.format(checkpoint_dir, filename))
+ logger.exception(
+ 'msg="ValueError when saving checkpoint data (perhaps invalid JSON)" checkpoint_dir="{}" filename="{}"'.
+ format(checkpoint_dir, filename))
except Exception:
- logger.exception('msg="Unknown exception when saving checkpoint data" checkpoint_dir="{}" filename="{}"'.format(checkpoint_dir, filename))
+ logger.exception(
+ 'msg="Unknown exception when saving checkpoint data" checkpoint_dir="{}" filename="{}"'.format(
+ checkpoint_dir, filename))
return success
def get_checkpoint_data(self, filename, checkpoint_dir=None, raise_known_exceptions=False):
@@ -727,11 +720,15 @@ def get_checkpoint_data(self, filename, checkpoint_dir=None, raise_known_excepti
with open(checkpoint_path, 'r') as fp:
data = json.load(fp)
except (IOError, ValueError) as e:
- logger.exception('msg="Exception when reading checkpoint data" checkpoint_dir="{}" filename="{}" exception="%s"'.format(checkpoint_dir, filename, e))
+ logger.exception(
+ 'msg="Exception when reading checkpoint data" checkpoint_dir="{}" filename="{}" exception="%s"'.format(
+ checkpoint_dir, filename, e))
if raise_known_exceptions:
raise
except Exception:
- logger.exception('msg="Unknown exception when reading checkpoint data" checkpoint_dir="{}" filename="{}"'.format(checkpoint_dir, filename))
+ logger.exception(
+ 'msg="Unknown exception when reading checkpoint data" checkpoint_dir="{}" filename="{}"'.format(
+ checkpoint_dir, filename))
raise
return data
@@ -741,7 +738,8 @@ def do_run(self, in_stream=sys.stdin, log_exception_and_continue=False):
Read the config from standard input and return the configuration.
in_stream -- The stream to get the input from (defaults to standard input)
- log_exception_and_continue -- If true, exceptions will not be thrown for invalid configurations and instead the stanza will be skipped.
+ log_exception_and_continue -- If true, exceptions will not be thrown for invalid configurations and instead the
+ stanza will be skipped.
"""
# Run the modular import
@@ -779,14 +777,12 @@ def do_run(self, in_stream=sys.stdin, log_exception_and_continue=False):
# Note: The "duration" parameter emulates the behavior of the "interval"
# parameter available on Splunk 6.x and higher, and is mainly used by the
# VMWare application.
-
- # TODO: A run() method may pass results back for optional processing
- results = None
+ # TODO: should we collect/process results from run()?
if stanzas:
if single_instance:
# Run the input across all defined stanzas and exit.
- results = self.run(stanzas, self._input_config)
+ self.run(stanzas, self._input_config)
else:
# Retrieve the single input stanza.
stanza = stanzas[0]
@@ -795,7 +791,8 @@ def do_run(self, in_stream=sys.stdin, log_exception_and_continue=False):
except ValueError as e:
# This should never happen unless the author of the modular input
# fails to specify "duration" as an IntegerField.
- logger.exception("Input stanza '%s' specified an invalid duration: %s" % (stanza.get('name', 'unknown'), str(e)))
+ logger.exception(
+ "Input stanza '%s' specified an invalid duration: %s" % (stanza.get('name', 'unknown'), str(e)))
# Exit with non-zero exit code so services/admin/inputstatus correctly reflects script status.
sys.exit(1)
@@ -805,7 +802,7 @@ def do_run(self, in_stream=sys.stdin, log_exception_and_continue=False):
# If there splunk 6.0 and interval field is defined, then ignore duration fields completely
if stanza.get("interval", -1) >= 0 and splunk.version.__version__ >= '6.0':
# Run the single stanza and exit.
- results = self.run(stanza, self._input_config)
+ self.run(stanza, self._input_config)
else:
# Run duration field
if duration > 0 and self.checkpoint_dir:
@@ -819,13 +816,13 @@ def do_run(self, in_stream=sys.stdin, log_exception_and_continue=False):
# use the name of the input itself, unhashed. Name collisions would
# be a configuration error.
self.save_checkpoint(self.checkpoint_dir, stanza_name, int(time.time()))
- results = self.run(stanza, )
+ self.run(stanza, self._input_config)
# Results processing, if any, could occur here.
time.sleep(ModularInput.time_to_next_run(self.checkpoint_dir, stanza_name, duration))
else:
# Duration is not defined
# Run the single stanza and exit for Splunk 5.x
- results = self.run(stanza, self._input_config)
+ self.run(stanza, self._input_config)
else:
logger.info("No input stanzas defined")
@@ -899,13 +896,11 @@ def _parse_args(self, argv):
parser = argparse.ArgumentParser(description='Modular input parameters')
- mode_args= parser.add_mutually_exclusive_group()
+ mode_args = parser.add_mutually_exclusive_group()
debug_args = parser.add_argument_group()
- debug_args.add_argument('--username', action="store", default=None,
- help="Splunk username (%s)" % warning_text)
- debug_args.add_argument('--password', action="store", default=None,
- help="Splunk password (%s)" % warning_text)
+ debug_args.add_argument('--username', action="store", default=None, help="Splunk username (%s)" % warning_text)
+ debug_args.add_argument('--password', action="store", default=None, help="Splunk password (%s)" % warning_text)
debug_args.add_argument('--infile', type=argparse.FileType(), default=None,
help="Filename containing XML modular input configuration (%s)" % warning_text)
@@ -936,7 +931,7 @@ def execute(self, in_stream=sys.stdin, out_stream=sys.stdout):
logger.info("Modular input: validate arguments called")
# Exit with a code of -1 if validation failed
- if self.do_validation() == False:
+ if self.do_validation() is False:
sys.exit(-1)
else:
@@ -959,7 +954,8 @@ def execute(self, in_stream=sys.stdin, out_stream=sys.stdout):
try:
self.do_run(args.infile, log_exception_and_continue=True)
except IOError:
- logger.exception("Modular input: modinput configuration could not be read from file %s.", args.infile.name)
+ logger.exception("Modular input: modinput configuration could not be read from file %s.",
+ args.infile.name)
else:
try:
self.do_run(in_stream, log_exception_and_continue=True)
@@ -1034,4 +1030,4 @@ def is_configured(self, app=None, assume_true_on_error=False):
except splunk.RESTException:
return assume_true_on_error
else:
- return assume_true_on_error
\ No newline at end of file
+ return assume_true_on_error
diff --git a/splunk_eventgen/splunk_app/lib/modinput/fields.py b/splunk_eventgen/splunk_app/lib/modinput/fields.py
index 40d6b37b..681ae6d5 100644
--- a/splunk_eventgen/splunk_app/lib/modinput/fields.py
+++ b/splunk_eventgen/splunk_app/lib/modinput/fields.py
@@ -11,7 +11,8 @@ class FieldValidationException(Exception):
class Field(object):
"""
- This is the base class that should be used to create field validators. Sub-class this and override to_python if you need custom validation.
+ This is the base class that should be used to create field validators. Sub-class this and override to_python if you
+ need custom validation.
"""
DATA_TYPE_STRING = 'string'
@@ -32,7 +33,8 @@ def __init__(self, name, title, description, required_on_create=True, required_o
Arguments:
name -- Set the name of the field (e.g. "database_server")
title -- Set the human readable title (e.g. "Database server")
- description -- Set the human readable description of the field (e.g. "The IP or domain name of the database server")
+ description -- Set the human-readable description of the field
+ (e.g. "The IP or domain name of the database server")
required_on_create -- If "true", the parameter is required on input stanza creation.
required_on_edit -- If "true", the parameter is required on input stanza modification.
@@ -70,7 +72,8 @@ def to_python(self, value):
def to_string(self, value):
"""
- Convert the field to a string value that can be returned. Should throw a FieldValidationException if the data is invalid.
+ Convert the field to a string value that can be returned. Should throw a FieldValidationException if the data is
+ invalid.
Arguments:
value -- The value to convert
@@ -80,7 +83,6 @@ def to_string(self, value):
class BooleanField(Field):
-
def to_python(self, value):
Field.to_python(self, value)
@@ -93,14 +95,15 @@ def to_python(self, value):
elif str(value).strip().lower() in ["false", "f", "0"]:
return False
- raise FieldValidationException("The value of '%s' for the '%s' parameter is not a valid boolean" % (str(value), self.name))
+ raise FieldValidationException(
+ "The value of '%s' for the '%s' parameter is not a valid boolean" % (str(value), self.name))
def to_string(self, value):
- if value == True:
+ if value is True:
return "1"
- elif value == False:
+ elif value is False:
return "0"
return str(value)
@@ -110,7 +113,6 @@ def get_data_type(self):
class DelimitedField(Field):
-
def __init__(self, name, title, description, delim, required_on_create=True, required_on_edit=False):
super(DelimitedField, self).__init__(name, title, description, required_on_create, required_on_edit)
self._delim = delim
@@ -154,17 +156,8 @@ class DurationField(Field):
WEEK = 604800
UNITS = {
- 'w': WEEK,
- 'week': WEEK,
- 'd': DAY,
- 'day': DAY,
- 'h': HOUR,
- 'hour': HOUR,
- 'm': MINUTE,
- 'min': MINUTE,
- 'minute': MINUTE,
- 's': 1
- }
+ 'w': WEEK, 'week': WEEK, 'd': DAY, 'day': DAY, 'h': HOUR, 'hour': HOUR, 'm': MINUTE, 'min': MINUTE, 'minute':
+ MINUTE, 's': 1}
def to_python(self, value):
Field.to_python(self, value)
@@ -174,7 +167,8 @@ def to_python(self, value):
# Make sure the duration could be parsed
if m is None:
- raise FieldValidationException("The value of '%s' for the '%s' parameter is not a valid duration" % (str(value), self.name))
+ raise FieldValidationException(
+ "The value of '%s' for the '%s' parameter is not a valid duration" % (str(value), self.name))
# Get the units and duration
d = m.groupdict()
@@ -185,11 +179,13 @@ def to_python(self, value):
try:
duration = int(d['duration'])
except ValueError:
- raise FieldValidationException("The duration '%s' for the '%s' parameter is not a valid number" % (d['duration'], self.name))
+ raise FieldValidationException(
+ "The duration '%s' for the '%s' parameter is not a valid number" % (d['duration'], self.name))
# Make sure the units are valid
if len(units) > 0 and units not in DurationField.UNITS:
- raise FieldValidationException("The unit '%s' for the '%s' parameter is not a valid unit of duration" % (units, self.name))
+ raise FieldValidationException(
+ "The unit '%s' for the '%s' parameter is not a valid unit of duration" % (units, self.name))
# Convert the units to seconds
if len(units) > 0:
@@ -202,7 +198,6 @@ def to_string(self, value):
class FloatField(Field):
-
def to_python(self, value):
Field.to_python(self, value)
@@ -227,7 +222,6 @@ def get_data_type(self):
class IntegerField(Field):
-
def to_python(self, value):
Field.to_python(self, value)
@@ -270,7 +264,8 @@ class IntervalField(Field):
# Note that we don't check explicitly for correct numeric values for each
# cron field.
- cron_rx = re.compile('''
+ cron_rx = re.compile(
+ '''
(
\d{1,2} # A digit.
|\d{1,2}-\d{1,2} # A range.
@@ -279,22 +274,20 @@ class IntervalField(Field):
|\* # The asterisk character.
|\*/\d{1,2} # An asterisk followed by a step.
)
- ''',
- re.VERBOSE
- )
+ ''', re.VERBOSE)
def to_python(self, value):
try:
# Try parsing the string as an integer.
- tmp = int(value)
- return value
+ return int(value)
except ValueError:
# Try parsing the string as a cron schedule.
if self.parse_cron(value):
return value
- raise FieldValidationException("The value of '{}' for the '{}' parameter is not a valid value".format(value, self.name))
+ raise FieldValidationException("The value of '{}' for the '{}' parameter is not a valid value".format(
+ value, self.name))
def get_data_type(self):
return Field.DATA_TYPE_STRING
@@ -309,14 +302,14 @@ def parse_cron(self, value):
class JsonField(Field):
-
def to_python(self, value):
Field.to_python(self, value)
try:
return json.loads(value)
except (TypeError, ValueError):
- raise FieldValidationException("The value of '%s' for the '%s' parameter is not a valid JSON object" % (str(value), self.name))
+ raise FieldValidationException(
+ "The value of '%s' for the '%s' parameter is not a valid JSON object" % (str(value), self.name))
def to_string(self, value):
return str(value)
@@ -326,7 +319,6 @@ def get_data_type(self):
class ListField(Field):
-
def to_python(self, value):
Field.to_python(self, value)
@@ -345,7 +337,6 @@ def to_string(self, value):
class RangeField(Field):
-
def __init__(self, name, title, description, low, high, required_on_create=True, required_on_edit=False):
super(RangeField, self).__init__(name, title, description, required_on_create, required_on_edit)
self.low = low
@@ -379,7 +370,6 @@ def get_data_type(self):
class RegexField(Field):
-
def to_python(self, value):
Field.to_python(self, value)
@@ -404,11 +394,7 @@ class SeverityField(Field):
# Note: We ignore "FATAL" severity since Python's logging assigns it the
# same value as "CRITICAL".
- SEVERITIES = {'DEBUG': 10,
- 'INFO': 20,
- 'WARN': 30,
- 'ERROR': 40,
- 'CRITICAL': 50}
+ SEVERITIES = {'DEBUG': 10, 'INFO': 20, 'WARN': 30, 'ERROR': 40, 'CRITICAL': 50}
SEVERITIES_BY_INT = {v: k for k, v in SEVERITIES.iteritems()}
@@ -421,7 +407,8 @@ def to_python(self, value):
# Did not receive a string for some reason.
pass
- raise FieldValidationException("The value of '{}' for the '{}' parameter is not a valid value".format(value, self.name))
+ raise FieldValidationException("The value of '{}' for the '{}' parameter is not a valid value".format(
+ value, self.name))
def to_string(self, value):
if value in SeverityField.SEVERITIES_BY_INT:
@@ -432,8 +419,8 @@ def to_string(self, value):
def get_data_type(self):
return Field.DATA_TYPE_NUMBER
-class VerbosityField(Field):
+class VerbosityField(Field):
def to_python(self, value):
Field.to_python(self, value)
@@ -455,4 +442,4 @@ def to_string(self, value):
return ""
def get_data_type(self):
- return Field.DATA_TYPE_NUMBER
\ No newline at end of file
+ return Field.DATA_TYPE_NUMBER
diff --git a/splunk_eventgen/splunk_app/lib/xmloutput.py b/splunk_eventgen/splunk_app/lib/xmloutput.py
index 5f378d0d..d1277166 100644
--- a/splunk_eventgen/splunk_app/lib/xmloutput.py
+++ b/splunk_eventgen/splunk_app/lib/xmloutput.py
@@ -1,9 +1,9 @@
-import xml.sax.saxutils
+import datetime
import logging
import logging.handlers
import sys
-import time
-import datetime
+import xml.sax.saxutils
+
from splunk.appserver.mrsparkle.lib.util import make_splunkhome_path
@@ -18,8 +18,8 @@ def setupLogger(logger=None, log_format='%(asctime)s %(levelname)s [ModInput] %(
logger.propagate = False # Prevent the log messages from being duplicated in the python.log file
logger.setLevel(level)
- file_handler = logging.handlers.RotatingFileHandler(make_splunkhome_path(['var', 'log', 'splunk', log_name]),
- maxBytes=2500000, backupCount=5)
+ file_handler = logging.handlers.RotatingFileHandler(
+ make_splunkhome_path(['var', 'log', 'splunk', log_name]), maxBytes=2500000, backupCount=5)
formatter = logging.Formatter(log_format)
file_handler.setFormatter(formatter)
@@ -30,22 +30,21 @@ def setupLogger(logger=None, log_format='%(asctime)s %(levelname)s [ModInput] %(
return logger
-########################################################################
-# COMMUNICATION WITH SPLUNKD
-# We provide a class for printing data out to splunkd. Essentially this
-# is just a wrapper on using xml formatted data delivery to splunkd
-########################################################################
+#########################################################################
+# COMMUNICATION WITH SPLUNKD #
+# We provide a class for printing data out to splunkd. Essentially this #
+# is just a wrapper on using xml formatted data delivery to splunkd #
+#########################################################################
class XMLOutputManager(object):
"""
- This guy handles writing data to splunkd with modular input xml
- streaming mode.
+ This guy handles writing data to splunkd with modular input xml streaming mode.
"""
def __init__(self, out=sys.stdout):
"""
- Construct an output manager.
- kwargs:
- out - represents the stream to print to. Defaults to sys.stdout.
+ Construct an output manager.
+ kwargs:
+ out - represents the stream to print to. Defaults to sys.stdout.
"""
self.stream_initiated = False
self.out = out
@@ -72,13 +71,13 @@ def sendData(self, buf, unbroken=None, sourcetype=None, source=None, host=None,
args:
buf - the buffer of data to send (string). REQUIRED.
kwargs:
- unbroken - this is a boolean indicating the buf passed is unbroken data if this is True.
+ unbroken - this is a boolean indicating the buf passed is unbroken data if this is True.
Defaults to False (buf is a single event).
sourcetype - the sourcetype to assign to the event (string). Defaults to input default.
source - the source to assign to the event (string). Defaults to input default.
host - the host to assign to the event (string). Defaults to input default.
- time - the time to assign to the event (string of UTC UNIX timestamp,
- miliseconds supported). Defaults to letting splunkd work it out.
+ time - the time to assign to the event (string of UTC UNIX timestamp,
+ milliseconds supported). Defaults to letting splunkd work it out.
index - the index into which the data should be stored. Defaults to the input default.
"""
if not unbroken:
@@ -107,7 +106,7 @@ def sendDoneKey(self, sourcetype=None, source=None, host=None, time=None, index=
"""
Let splunkd know that previously sent, unbroken events are now complete
and ready for processing. Typically you will send some data, like chunks of a log file
- then when you know you are done, say at the end of the log file you will send a
+ then when you know you are done, say at the end of the log file you will send a
done key to indicate that sent data may be processed for the provided source,
sourcetype, host, and index
kwargs:
@@ -135,4 +134,4 @@ def sendDoneKey(self, sourcetype=None, source=None, host=None, time=None, index=
# prints XML error data to be consumed by Splunk
def printError(self, s):
- self.out.write("{0}".format(xml.sax.saxutils.escape(s)))
\ No newline at end of file
+ self.out.write("{0}".format(xml.sax.saxutils.escape(s)))
diff --git a/splunk_eventgen/version.json b/splunk_eventgen/version.json
index 07e6fd0f..1047d698 100644
--- a/splunk_eventgen/version.json
+++ b/splunk_eventgen/version.json
@@ -1 +1 @@
-{"version": "6.3.4"}
+{"version": "6.3.5"}
\ No newline at end of file
diff --git a/tests/.gitignore b/tests/.gitignore
index 0d20b648..0dde16b9 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1 +1,2 @@
*.pyc
+results/
diff --git a/tests/large/README.md b/tests/large/README.md
new file mode 100644
index 00000000..74380daf
--- /dev/null
+++ b/tests/large/README.md
@@ -0,0 +1,12 @@
+Convention:
+* Test conf files are located at `conf` folder;
+* Sample files are located at `sample` folder;
+* Other utils related tools are located at `utils` folder;
+* `fileName` in `conf` settings is relative which will write results to folder `tests/large/results`;
+
+How to add a new functional test:
+* Add eventgen conf file in `conf` folder;(`sampleDir = tests/large/sample` should be in the conf)
+* Add sample file defined in above eventgen conf in folder `sample`;
+* Add a new functional test `py` file and add test case;
+* Use `eventgen_test_helper` fixture to create a helper instance and use `get_events()` to get events generated;
+* Pass `timeout=60` if you want to stop eventgen instance after 60s;
diff --git a/tests/large/conf/eventgen_replay.conf b/tests/large/conf/eventgen_replay.conf
new file mode 100755
index 00000000..c919f072
--- /dev/null
+++ b/tests/large/conf/eventgen_replay.conf
@@ -0,0 +1,14 @@
+[replay]
+sampleDir = tests/large/sample
+mode = replay
+sampletype = raw
+outputMode = stdout
+end = 1
+
+token.0.token = \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
+token.0.replacementType = replaytimestamp
+token.0.replacement = %Y-%m-%d %H:%M:%S
+
+token.1.token = @@integer
+token.1.replacementType = random
+token.1.replacement = integer[0:10]
diff --git a/tests/large/conf/eventgen_replay_backfill.conf b/tests/large/conf/eventgen_replay_backfill.conf
new file mode 100644
index 00000000..c8e0b1ca
--- /dev/null
+++ b/tests/large/conf/eventgen_replay_backfill.conf
@@ -0,0 +1,15 @@
+[replay]
+sampleDir = tests/large/sample
+backfill = -5s
+sampletype = raw
+outputMode = stdout
+mode = replay
+end = 2
+
+token.0.token = \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
+token.0.replacementType = replaytimestamp
+token.0.replacement = %Y-%m-%d %H:%M:%S
+
+token.1.token = @@integer
+token.1.replacementType = random
+token.1.replacement = integer[0:10]
diff --git a/tests/large/conf/eventgen_replay_csv.conf b/tests/large/conf/eventgen_replay_csv.conf
new file mode 100755
index 00000000..a00ca925
--- /dev/null
+++ b/tests/large/conf/eventgen_replay_csv.conf
@@ -0,0 +1,10 @@
+[timeorder]
+sampleDir = tests/large/sample
+mode = replay
+sampletype = csv
+timeField = _time
+outputMode = stdout
+
+token.0.token = \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}
+token.0.replacementType = replaytimestamp
+token.0.replacement = %Y-%m-%dT%H:%M:%S
diff --git a/tests/large/conf/eventgen_replay_end_1.conf b/tests/large/conf/eventgen_replay_end_1.conf
new file mode 100755
index 00000000..f9295a8f
--- /dev/null
+++ b/tests/large/conf/eventgen_replay_end_1.conf
@@ -0,0 +1,15 @@
+[replay]
+sampleDir = tests/large/sample
+mode = replay
+earliest = -5s
+sampletype = raw
+outputMode = stdout
+end = 2
+
+token.0.token = \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
+token.0.replacementType = replaytimestamp
+token.0.replacement = %Y-%m-%d %H:%M:%S
+
+token.1.token = @@integer
+token.1.replacementType = random
+token.1.replacement = integer[0:10]
diff --git a/tests/large/conf/eventgen_replay_end_2.conf b/tests/large/conf/eventgen_replay_end_2.conf
new file mode 100755
index 00000000..afbcb35a
--- /dev/null
+++ b/tests/large/conf/eventgen_replay_end_2.conf
@@ -0,0 +1,15 @@
+[replay]
+sampleDir = tests/large/sample
+mode = replay
+earliest = -5s
+sampletype = raw
+outputMode = stdout
+end = -1
+
+token.0.token = \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
+token.0.replacementType = replaytimestamp
+token.0.replacement = %Y-%m-%d %H:%M:%S
+
+token.1.token = @@integer
+token.1.replacementType = random
+token.1.replacement = integer[0:10]
diff --git a/tests/large/conf/eventgen_replay_timeMultiple.conf b/tests/large/conf/eventgen_replay_timeMultiple.conf
new file mode 100755
index 00000000..c51ff32b
--- /dev/null
+++ b/tests/large/conf/eventgen_replay_timeMultiple.conf
@@ -0,0 +1,14 @@
+[replay]
+sampleDir = tests/large/sample
+mode = replay
+sampletype = raw
+outputMode = stdout
+timeMultiple = 0.5
+
+token.0.token = \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
+token.0.replacementType = replaytimestamp
+token.0.replacement = %Y-%m-%d %H:%M:%S
+
+token.1.token = @@integer
+token.1.replacementType = random
+token.1.replacement = integer[0:10]
diff --git a/tests/large/conf/eventgen_sample.conf b/tests/large/conf/eventgen_sample.conf
new file mode 100755
index 00000000..657ec987
--- /dev/null
+++ b/tests/large/conf/eventgen_sample.conf
@@ -0,0 +1,15 @@
+[sample]
+sampleDir = tests/large/sample
+mode = sample
+earliest = -15s
+sampletype = raw
+outputMode = stdout
+end = 1
+
+token.0.token = \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
+token.0.replacementType = timestamp
+token.0.replacement = %Y-%m-%d %H:%M:%S
+
+token.1.token = @@integer
+token.1.replacementType = random
+token.1.replacement = integer[0:10]
diff --git a/tests/large/conf/eventgen_sample_backfill.conf b/tests/large/conf/eventgen_sample_backfill.conf
new file mode 100755
index 00000000..8c9d56ac
--- /dev/null
+++ b/tests/large/conf/eventgen_sample_backfill.conf
@@ -0,0 +1,15 @@
+[sample]
+sampleDir = tests/large/sample
+mode = sample
+backfill = -15s
+sampletype = raw
+outputMode = stdout
+end = 1
+
+token.0.token = \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
+token.0.replacementType = timestamp
+token.0.replacement = %Y-%m-%d %H:%M:%S
+
+token.1.token = @@integer
+token.1.replacementType = random
+token.1.replacement = integer[0:10]
diff --git a/tests/large/conf/eventgen_sample_breaker.conf b/tests/large/conf/eventgen_sample_breaker.conf
new file mode 100755
index 00000000..99a41ded
--- /dev/null
+++ b/tests/large/conf/eventgen_sample_breaker.conf
@@ -0,0 +1,14 @@
+[breakersample]
+sampleDir = tests/large/sample
+outputMode = file
+fileName = tests/large/results/eventgen_sample_breaker.result
+count = 3
+earliest = -3s
+latest = now
+interval = 3
+breaker = ^\d{14}\.\d{6}
+end = 1
+
+token.0.token = ^(\d{14})\.\d{6}
+token.0.replacementType = timestamp
+token.0.replacement = %Y%m%d%H%M%S
diff --git a/tests/large/conf/eventgen_sample_count.conf b/tests/large/conf/eventgen_sample_count.conf
new file mode 100755
index 00000000..688c4b0f
--- /dev/null
+++ b/tests/large/conf/eventgen_sample_count.conf
@@ -0,0 +1,16 @@
+[sample]
+sampleDir = tests/large/sample
+mode = sample
+earliest = -15s
+sampletype = raw
+outputMode = stdout
+end = 1
+count = 5
+
+token.0.token = \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
+token.0.replacementType = timestamp
+token.0.replacement = %Y-%m-%d %H:%M:%S
+
+token.1.token = @@integer
+token.1.replacementType = random
+token.1.replacement = integer[0:10]
diff --git a/tests/large/conf/eventgen_sample_csv.conf b/tests/large/conf/eventgen_sample_csv.conf
new file mode 100755
index 00000000..18065dac
--- /dev/null
+++ b/tests/large/conf/eventgen_sample_csv.conf
@@ -0,0 +1,14 @@
+[timeorder]
+sampleDir = tests/large/sample
+mode = sample
+sampletype = csv
+outputMode = stdout
+end = 1
+
+token.0.token = \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
+token.0.replacementType = timestamp
+token.0.replacement = %Y-%m-%d %H:%M:%S
+
+token.1.token = @@integer
+token.1.replacementType = random
+token.1.replacement = integer[0:10]
diff --git a/tests/large/conf/eventgen_sample_earliest.conf b/tests/large/conf/eventgen_sample_earliest.conf
new file mode 100755
index 00000000..8c505b14
--- /dev/null
+++ b/tests/large/conf/eventgen_sample_earliest.conf
@@ -0,0 +1,16 @@
+[sample]
+sampleDir = tests/large/sample
+mode = sample
+earliest = -15s
+sampletype = raw
+outputMode = file
+fileName = tests/large/results/eventgen_sample_earliest.result
+end = 1
+
+token.0.token = \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
+token.0.replacementType = timestamp
+token.0.replacement = %Y-%m-%d %H:%M:%S
+
+token.1.token = @@integer
+token.1.replacementType = random
+token.1.replacement = integer[0:10]
diff --git a/tests/large/conf/eventgen_sample_end.conf b/tests/large/conf/eventgen_sample_end.conf
new file mode 100755
index 00000000..9918bc79
--- /dev/null
+++ b/tests/large/conf/eventgen_sample_end.conf
@@ -0,0 +1,16 @@
+[sample]
+sampleDir = tests/large/sample
+mode = sample
+earliest = -15s
+sampletype = raw
+outputMode = file
+fileName = tests/large/results/eventgen_sample_end.result
+end = 1
+
+token.0.token = \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
+token.0.replacementType = timestamp
+token.0.replacement = %Y-%m-%d %H:%M:%S
+
+token.1.token = @@integer
+token.1.replacementType = random
+token.1.replacement = integer[0:10]
diff --git a/tests/large/conf/eventgen_sample_interval.conf b/tests/large/conf/eventgen_sample_interval.conf
new file mode 100755
index 00000000..74d95c8a
--- /dev/null
+++ b/tests/large/conf/eventgen_sample_interval.conf
@@ -0,0 +1,15 @@
+[sample]
+sampleDir = tests/large/sample
+mode = sample
+sampletype = raw
+outputMode = file
+fileName = tests/large/results/eventgen_sample_interval.result
+interval = 10
+
+token.0.token = \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
+token.0.replacementType = timestamp
+token.0.replacement = %Y-%m-%d %H:%M:%S
+
+token.1.token = @@integer
+token.1.replacementType = random
+token.1.replacement = integer[0:10]
diff --git a/tests/large/conf/eventgen_sample_latest.conf b/tests/large/conf/eventgen_sample_latest.conf
new file mode 100755
index 00000000..00ff18aa
--- /dev/null
+++ b/tests/large/conf/eventgen_sample_latest.conf
@@ -0,0 +1,16 @@
+[sample]
+sampleDir = tests/large/sample
+mode = sample
+latest = +15s
+sampletype = raw
+outputMode = file
+fileName = tests/large/results/eventgen_sample_latest.result
+end = 1
+
+token.0.token = \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
+token.0.replacementType = timestamp
+token.0.replacement = %Y-%m-%d %H:%M:%S
+
+token.1.token = @@integer
+token.1.replacementType = random
+token.1.replacement = integer[0:10]
diff --git a/tests/large/conf/eventgen_token_replacement.conf b/tests/large/conf/eventgen_token_replacement.conf
new file mode 100755
index 00000000..9b521e4b
--- /dev/null
+++ b/tests/large/conf/eventgen_token_replacement.conf
@@ -0,0 +1,62 @@
+[tokenreplacement.sample]
+sampleDir = tests/large/sample
+mode = sample
+sampletype = raw
+outputMode = stdout
+end = 1
+
+token.0.token = "start":"(\d+)
+token.0.replacementType = timestamp
+token.0.replacement = %s
+
+token.1.token = "cp":"([\d\.]+)
+token.1.replacementType = file
+token.1.replacement = tests/large/sample/cp.csv
+
+token.2.token = "country":"(\w+)
+token.2.replacementType = mvfile
+token.2.replacement = tests/large/sample/city.csv:1
+
+token.3.token = "city":"(\w+)
+token.3.replacementType = file
+token.3.replacement = tests/large/sample/city.csv:2
+
+token.4.token = "lat":"(-?\d+.\d+)
+token.4.replacementType = file
+token.4.replacement = tests/large/sample/city.csv:4
+
+token.5.token = "long":"(-?\d+.\d+)
+token.5.replacementType = file
+token.5.replacement = tests/large/sample/city.csv:5
+
+token.6.token = "id":"([\w\-]+)
+token.6.replacementType = file
+token.6.replacement = tests/large/sample/id.csv
+
+token.7.token = "bytes":"(\d+)
+token.7.replacementType = random
+token.7.replacement = integer[40:5000]
+
+token.8.token = "cliIP":"(\d+.\d+.\d+.\d+)
+token.8.replacementType = file
+token.8.replacement = tests/large/sample/ip.csv
+
+token.9.token = "lastByte":"(\d+)
+token.9.replacementType = static
+token.9.replacement = 0
+
+token.10.token = "receiver_id":"(\d*)
+token.10.replacementType = integerid
+token.10.replacement = 1
+
+token.11.token = "Ak_IP":"(\d+.\d+.\d+.\d+)
+token.11.replacementType = random
+token.11.replacement = ipv4
+
+token.12.token = "forward-origin-ip":"(\d+.\d+.\d+.\d+)
+token.12.replacementType = random
+token.12.replacement = ipv6
+
+token.13.token = "end-user-ip":"(\d+.\d+.\d+.\d+)
+token.13.replacementType = random
+token.13.replacement = mac
diff --git a/tests/large/conftest.py b/tests/large/conftest.py
new file mode 100644
index 00000000..60663dd6
--- /dev/null
+++ b/tests/large/conftest.py
@@ -0,0 +1,18 @@
+import pytest
+
+from utils.eventgen_test_helper import EventgenTestHelper
+
+
+@pytest.fixture
+def eventgen_test_helper():
+ """Returns a function to create EventgenTestHelper instance based on config file"""
+ created_instances = []
+
+ def _create_eventgen_test_helper_instance(conf, timeout=None):
+ instance = EventgenTestHelper(conf, timeout)
+ created_instances.append(instance)
+ return instance
+ yield _create_eventgen_test_helper_instance
+
+ for instance in created_instances:
+ instance.tear_down()
diff --git a/tests/large/results/__init__.py b/tests/large/results/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/large/sample/breakersample b/tests/large/sample/breakersample
new file mode 100755
index 00000000..51304b28
--- /dev/null
+++ b/tests/large/sample/breakersample
@@ -0,0 +1,9 @@
+20110414114247.083068
+PercentProcessorTime=@@proc_time
+PercentUserTime=37
+wmi_type=CPUTime
+
+20110414114247.083068
+PercentProcessorTime=100
+PercentUserTime=37
+wmi_type=CPUTime
diff --git a/tests/large/sample/city.csv b/tests/large/sample/city.csv
new file mode 100644
index 00000000..e9a15c34
--- /dev/null
+++ b/tests/large/sample/city.csv
@@ -0,0 +1,7472 @@
+US,ATLANTA,GA,33.7486,-84.3884,23.74.2.12
+US,WASHINGTON,DC,38.9102,-77.0179,204.93.39.36
+GB,LONDON,EN,51.50,-0.12,88.221.87.112
+TW,TAIPEI,"",25.02,121.45,61.220.62.171
+US,AUSTIN,TX,30.2669,-97.7429,23.215.15.32
+AU,BRISBANE,QLD,-27.50,153.02,210.11.142.64
+US,LOSANGELES,CA,33.9733,-118.2487,173.223.52.67
+CA,VANCOUVER,BC,49.25,-123.13,24.244.17.205
+CA,MONTREAL,QC,45.50,-73.58,72.246.43.237
+DE,FRANKFURT,HE,50.12,8.68,2.20.142.166
+US,POTTSTOWN,PA,40.2616,-75.6182,184.26.44.42
+UA,KIEV,"",50.43,30.52,80.239.222.190
+CA,TORONTO,ON,43.67,-79.42,165.254.48.150
+US,MILILANI,HI,21.4601,-157.9603,23.67.56.205
+EC,GUAYAQUIL,"",-2.17,-79.90,23.74.2.7
+CN,GUANGZHOU,GD,23.12,113.25,72.246.191.16
+MX,GUADALAJARA,JAL,20.67,-103.33,107.14.32.235
+VN,SAIGON,"",10.75,106.67,184.84.239.186
+US,NEWYORK,NY,40.7500,-73.9967,209.170.113.237
+US,PRINEVILLE,OR,44.3258,-120.6504,23.79.240.37
+CA,CALGARY,AB,51.08,-114.08,24.244.17.197
+US,SANANTONIO,TX,29.4697,-98.5294,165.254.96.242
+US,SAINTPETERSBURG,FL,27.7710,-82.6368,23.74.2.12
+US,MOUNTAINVIEW,CA,37.4154,-122.0585,63.80.12.225
+US,CHARLOTTESVILLE,VA,38.0464,-78.4686,184.26.44.42
+US,JACKSONVILLE,FL,30.3383,-81.7706,23.79.240.48
+US,DALLAS,TX,32.7874,-96.7989,23.212.53.64
+US,CHICAGO,IL,41.8643,-87.645,23.79.255.153
+IN,KOLKATA,WB,22.57,88.37,23.57.76.18
+US,ROSEVILLE,CA,38.7399,-121.2479,23.61.195.149
+US,PATERSON,NJ,40.9126,-74.171,184.51.125.79
+DE,HERBORN,HE,50.68,8.32,23.14.94.228
+GE,TBILISI,"",41.72,44.78,80.15.235.171
+US,GOLETA,CA,34.4356,-119.8269,184.50.26.179
+LV,RIGA,"",56.95,24.10,2.21.240.40
+NZ,AUCKLAND,"",-36.87,174.77,184.28.126.7
+KR,ANYANG,"",37.39,126.93,125.56.214.147
+HK,HONGKONG,"",22.28,114.15,219.76.10.103
+IT,MILANO,"",45.47,9.20,193.45.15.199
+US,SUNNYVALE,CA,37.3873,-122.0158,23.212.52.82
+US,INDEPENDENCE,MO,39.1129,-94.4077,23.77.234.11
+DE,WILHELMSHAVEN,NI,53.52,8.13,2.20.142.166
+US,RIVERFOREST,IL,41.8950,-87.8194,23.67.60.220
+US,REDWOODCITY,CA,37.4611,-122.2355,23.61.195.150
+IN,BHOPAL,MP,23.27,77.40,96.17.180.175
+CN,NANNING,GX,22.82,108.32,184.51.199.145
+CN,BEIJING,BJ,39.90,116.41,184.51.199.132
+US,FRESNO,CA,36.8419,-119.7952,23.212.52.79
+US,MCKINNEY,TX,33.2109,-96.5677,107.14.43.30
+FR,SAINTDENIS,"",48.93,2.37,217.89.107.179
+US,MODESTO,CA,37.6733,-121.0107,96.17.12.44
+UA,KERCH,CRIMEA,45.36,36.48,2.22.52.109
+US,WILMINGTON,CA,33.7841,-118.2613,184.87.195.109
+SG,SINGAPORE,"",1.29,103.86,23.75.23.135
+US,GERMANTOWN,MD,39.1292,-77.2953,23.192.161.16
+US,SAINTLOUIS,MO,38.6312,-90.1926,96.17.14.16
+TH,BANGKOK,"",13.75,100.52,23.14.94.228
+US,PORTLAND,OR,45.4978,-122.6937,67.131.104.14
+US,UNIONCITY,CA,37.5970,-122.059,96.17.12.44
+US,SEATTLE,WA,47.6115,-122.3343,184.27.179.187
+US,FORTCOLLINS,CO,40.5917,-105.129,63.235.21.141
+US,ROCHESTER,NY,43.1544,-77.6156,107.14.38.227
+PH,ROOSEVELT,"",12.73,123.70,202.78.83.175
+US,SALTLAKECITY,UT,40.7566,-111.8992,23.212.53.75
+AU,RIVERWOOD,NSW,-33.95,151.05,23.62.8.25
+US,GLENDALE,CA,34.1697,-118.2902,184.87.195.99
+AU,CANBERRA,ACT,-35.28,149.22,60.254.143.114
+US,SPRINGFIELD,MO,37.2155,-93.2981,23.77.234.11
+US,KANSASCITY,MO,39.1034,-94.6,23.63.227.227
+US,MARTIN,TN,36.3557,-88.8417,23.79.240.36
+US,BRIDGEVIEW,IL,41.7407,-87.8064,23.67.60.222
+US,HOMESTEAD,FL,25.4848,-80.5094,23.79.240.48
+ZA,CAPETOWN,"",-33.92,18.42,41.193.163.53
+US,WAUKEE,IA,41.6100,-93.8635,23.67.60.217
+FR,NICE,"",43.70,7.25,2.16.117.190
+US,WESTPALMBEACH,FL,26.7174,-80.0695,184.51.207.103
+US,JACKSON,MS,32.2896,-90.1841,23.79.240.36
+US,BUFFALO,NY,42.8954,-78.8862,23.63.227.227
+US,INDIANAPOLIS,IN,39.7745,-86.1096,65.113.249.8
+DE,DUSSELDORF,NW,51.22,6.77,92.122.207.164
+MX,MEXICOCITY,DIF,19.43,-99.14,23.216.10.54
+ES,MADRID,"",40.40,-3.68,92.123.73.233
+CN,FUZHOU,FJ,26.08,119.30,72.246.191.16
+US,DETROIT,MI,42.3465,-83.0598,23.62.100.152
+US,SANTAFE,NM,35.7998,-105.9892,184.84.180.97
+US,MADISON,WI,43.0733,-89.4012,184.85.215.165
+US,GLASGOW,KY,36.9602,-85.9175,65.113.249.8
+US,FAIRFAX,SC,32.8821,-81.3268,64.86.201.118
+AU,SYDNEY,NSW,-33.88,151.22,184.28.17.55
+US,RANTOUL,IL,40.3044,-88.1569,23.67.60.223
+US,NORMAN,OK,35.2227,-97.4395,23.215.15.9
+IN,BHANDUP,MH,19.15,72.93,23.57.69.157
+GB,EALING,EN,51.50,-0.32,173.222.211.203
+US,MILWAUKEE,WI,43.0386,-87.9067,23.74.8.24
+US,BROOKLYN,NY,40.6944,-73.9902,184.26.44.42
+JP,TOKYO,13,35.69,139.75,23.15.1.15
+DE,HAMBURG,HH,53.55,10.00,194.25.95.214
+US,PHOENIX,AZ,33.4486,-112.0733,184.50.26.179
+US,RALEIGH,NC,35.7750,-78.6336,184.27.45.157
+LT,VILNIUS,"",54.68,25.32,2.21.240.40
+US,ORLANDO,FL,28.5418,-81.3736,23.33.186.101
+US,FREMONT,CA,37.5710,-121.9858,23.61.195.150
+CA,EDMONTON,AB,53.55,-113.50,65.113.249.11
+US,SMYRNA,GA,33.8714,-84.4998,184.51.35.226
+MY,KUALALUMPUR,"",3.17,101.70,58.26.185.125
+ES,VALENCIA,"",39.47,-0.37,213.248.113.118
+US,TEMPE,AZ,33.4148,-111.9088,184.50.26.201
+US,MIAMI,FL,25.7738,-80.1936,23.79.240.48
+BG,STARAZAGORA,"",42.42,25.63,23.62.237.133
+KE,NAIROBI,"",-1.28,36.82,95.101.2.112
+UA,KHARKIV,"",50.00,36.25,2.22.52.102
+US,MARIETTA,GA,33.9527,-84.5502,23.79.240.36
+FR,PARIS,"",48.87,2.33,23.212.108.8
+US,HUMBOLDT,IA,42.7370,-94.1578,23.63.227.214
+US,OAKLAND,NJ,41.0312,-74.241,184.51.125.79
+GB,BIRMINGHAM,EN,52.47,-1.92,23.67.255.106
+US,SANFRANCISCO,CA,37.7795,-122.4195,96.17.12.44
+FR,LYON,"",45.75,4.85,23.62.237.137
+RU,TOMSK,"",56.50,84.97,2.21.240.40
+DE,NEUISENBURG,HE,50.05,8.70,77.67.27.231
+US,RICHLAND,WA,46.3844,-119.3775,184.27.179.187
+US,HIALEAH,FL,25.8579,-80.2783,23.79.240.36
+US,TACOMA,WA,47.2534,-122.4432,23.212.59.64
+US,DURHAM,NC,35.9993,-78.8978,209.18.41.23
+AU,MELBOURNE,VIC,-37.82,144.97,60.254.143.211
+LU,LUXEMBOURG,"",49.61,6.13,77.67.27.250
+CH,ZURICH,"",47.37,8.55,194.25.95.225
+US,MAULDIN,SC,34.7791,-82.3072,23.79.240.48
+GB,RENFREW,SC,55.87,-4.37,88.221.87.94
+US,DIAMONDBAR,CA,33.9944,-117.8149,184.50.26.179
+US,ASHBURN,VA,39.0438,-77.4879,96.6.47.106
+US,OREM,UT,40.3142,-111.7099,184.84.180.68
+US,MENLOPARK,CA,37.4524,-122.1842,23.212.52.88
+US,TORRANCE,CA,33.8331,-118.3144,23.216.10.78
+US,SANDIEGO,CA,32.7253,-117.1721,63.151.119.16
+IN,HYDERABAD,AP,17.38,78.47,23.57.69.156
+US,WARRENSBURG,MO,38.8247,-93.6796,204.93.47.216
+US,SANLORENZO,CA,37.6786,-122.133,184.84.180.101
+DE,KOLN,NW,50.93,6.95,23.14.94.228
+VN,HANOI,"",21.03,105.85,23.76.205.111
+US,BOISE,ID,43.6139,-116.2025,206.104.149.146
+US,CANALWINCHESTER,OH,39.8265,-82.7973,96.17.9.14
+US,SACRAMENTO,CA,38.5819,-121.4935,96.17.12.48
+US,ELOY,AZ,32.6521,-111.6069,173.223.52.70
+US,BOWLINGGREEN,KY,37.1031,-86.4201,107.14.38.224
+AU,CARLINGFORD,NSW,-33.78,151.05,23.62.8.25
+KR,SEOUL,"",37.57,127.00,61.111.58.43
+US,REDMOND,WA,47.6833,-122.1231,184.27.179.159
+RO,DEVA,"",45.88,22.90,81.196.26.236
+IN,BANGALORE,KA,12.98,77.58,122.178.225.70
+RU,MOSCOW,"",55.75,37.58,217.212.227.25
+US,BEDFORD,PA,39.9363,-78.5519,205.185.195.170
+US,MOUNTEPHRAIM,NJ,39.8811,-75.0919,184.26.44.38
+DE,BERLIN,BE,52.52,13.40,23.14.94.220
+SE,STOCKHOLM,AB,59.33,18.05,2.21.240.40
+US,GASTONIA,NC,35.2205,-81.2501,63.141.200.241
+US,MAITLAND,FL,28.6318,-81.3625,23.33.186.101
+US,PUYALLUP,WA,47.1905,-122.3289,23.212.59.90
+US,COEURDALENE,ID,47.6719,-116.5794,107.14.43.30
+DE,REGENSBURG,BY,49.02,12.10,194.25.95.214
+PL,WARSAW,"",52.25,21.00,2.22.52.109
+CN,SHENYANG,LN,41.80,123.41,184.50.87.176
+DE,HEILBRONN,BW,49.14,9.22,92.122.215.89
+US,SANTAROSA,CA,38.4507,-122.7923,96.17.12.44
+US,SANDY,UT,40.5769,-111.8884,63.151.119.25
+AR,MUNRO,"",-34.53,-58.55,80.239.222.167
+US,SANTACLARA,CA,37.3519,-121.952,23.204.109.61
+MT,MELITA,"",35.89,14.40,193.45.15.199
+IE,DUBLIN,"",53.33,-6.25,88.221.222.33
+IN,NEWDELHI,DL,28.60,77.20,23.57.69.157
+US,DESMOINES,IA,41.6006,-93.6087,23.67.60.223
+US,GREENVILLE,NC,35.6116,-77.3732,184.28.17.76
+AT,EGGENBURG,"",48.63,15.82,195.145.147.107
+US,WALNUT,CA,34.0203,-117.8647,184.50.26.179
+US,SALEM,OR,44.9053,-122.9167,23.212.59.63
+US,CENTREVILLE,VA,38.8530,-77.4732,23.67.242.139
+PK,FAZAL,"",26.63,69.53,23.5.165.168
+JP,NAGOYA,23,35.17,136.92,72.246.191.19
+RU,PROGRESS,"",53.88,37.85,80.239.222.169
+US,LEXINGTON,KY,38.0142,-84.4842,23.74.8.24
+DK,COPENHAGEN,"",55.67,12.58,2.21.240.61
+BR,RIODEJANEIRO,RJ,-22.90,-43.23,177.159.174.13
+US,CANYONCOUNTRY,CA,34.4009,-118.3941,184.50.26.194
+US,NASHVILLE,TN,36.1649,-86.7761,23.67.60.223
+US,FULTON,MO,38.8555,-91.9568,23.79.255.153
+US,MONROE,LA,32.5324,-92.1046,65.113.249.8
+CA,REGINA,SK,50.45,-104.62,184.27.179.181
+UA,LVIV,"",49.83,24.00,23.14.94.224
+US,MORGANHILL,CA,37.2101,-121.5392,23.216.10.78
+US,HAYS,KS,38.8338,-99.3297,165.254.96.248
+US,PASADENA,CA,34.1465,-118.1393,23.216.10.54
+LV,ILGUCIEMS,"",56.97,24.07,2.21.240.61
+US,SANJOSE,CA,37.3435,-121.8887,23.61.195.165
+ID,JAKARTA,"",-6.17,106.80,23.0.162.46
+US,NEWBALTIMORE,MI,42.6814,-82.776,23.67.60.222
+US,HOUSTON,TX,29.7634,-95.3634,23.215.15.22
+RS,BELGRADE,"",44.82,20.47,23.62.237.135
+IN,CHENNAI,TN,13.08,80.28,23.205.118.106
+US,MENOMONEEFALLS,WI,43.1490,-88.1221,65.113.249.8
+US,WINDER,GA,33.9995,-83.6956,23.79.240.36
+US,SHERMANOAKS,CA,34.1460,-118.4632,184.50.26.203
+SA,RIYADH,"",24.64,46.77,80.239.237.231
+US,NORTHRIDGE,CA,34.2385,-118.5501,184.50.26.179
+US,FORTWORTH,TX,32.7254,-97.3208,96.17.177.63
+US,STAMFORD,CT,41.0531,-73.5379,65.113.249.11
+GB,BELFAST,NI,54.58,-5.93,23.212.108.28
+US,GRANDFORKS,ND,47.8810,-97.0607,107.14.38.217
+US,HOMEWOOD,IL,41.5602,-87.657,23.67.60.223
+US,LOUISVILLE,KY,38.2545,-85.7595,107.14.38.227
+US,SANTACRUZ,CA,37.0412,-122.124,23.61.195.163
+HU,BUDAPEST,"",47.50,19.08,46.33.70.104
+US,MILESCITY,MT,46.3777,-105.7778,23.215.15.32
+US,PALMDALE,CA,34.4834,-118.0804,184.50.26.179
+DE,DARMSTADT,HE,49.87,8.65,194.25.95.212
+GB,CROYDON,EN,51.38,-0.10,23.67.255.158
+AR,BUENOSAIRES,"",-34.59,-58.67,190.98.167.220
+FR,AMIENS,"",49.90,2.30,2.20.243.45
+US,NOVI,MI,42.4713,-83.5253,184.26.93.116
+US,FREEPORT,NY,40.6517,-73.5837,184.26.44.38
+US,BALTIMORE,MD,39.2940,-76.6226,23.67.242.139
+AU,PERTH,WA,-31.93,115.83,184.86.223.76
+US,LAKEJACKSON,TX,29.0424,-95.4739,23.215.15.9
+US,STATECOLLEGE,PA,40.8020,-77.8329,63.216.54.216
+US,NAPA,CA,38.3929,-122.2917,23.212.52.79
+US,BRUNSWICK,OH,41.2414,-81.829,107.14.32.235
+US,ELCENTRO,CA,32.7712,-115.5933,184.50.26.179
+US,CHULAVISTA,CA,32.6403,-117.0834,23.220.149.114
+IL,HAIFA,"",32.82,34.99,212.143.162.162
+US,GEORGETOWN,TX,30.6233,-97.6645,204.2.223.90
+US,SAGINAW,MI,43.4083,-83.8878,23.63.227.227
+BG,SOFIA,"",42.68,23.32,23.62.237.133
+CA,BURNABY,BC,49.25,-122.95,24.244.17.197
+US,CULVERCITY,CA,33.9886,-118.3988,165.254.51.142
+CA,OTTAWA,ON,45.42,-75.70,107.14.38.227
+IT,ROME,"",41.90,12.48,95.101.34.109
+BR,BRASILIA,DF,-15.78,-47.92,2.22.52.102
+US,SCOTTSDALE,AZ,33.5251,-111.8956,63.226.34.173
+JP,MARUNOUCHI,13,35.68,139.77,104.74.70.105
+RO,CONSTANTA,"",44.18,28.65,81.196.26.236
+US,TEMECULA,CA,33.4939,-117.1475,184.50.26.179
+US,SARALAND,AL,30.8789,-88.1101,96.17.153.162
+PK,LAHORE,"",31.57,74.32,79.140.94.234
+US,NEWARK,CA,37.5187,-122.045,96.17.12.48
+US,OLYMPIA,WA,46.9755,-122.8721,184.84.180.101
+US,RENTON,WA,47.4624,-122.211,23.212.59.85
+PH,MAKATI,"",14.57,121.03,58.71.107.120
+FR,GRENOBLE,"",45.17,5.72,2.20.243.42
+DE,ROTTWEIL,BW,48.17,8.62,194.25.95.225
+US,REDFORD,MI,42.3767,-83.2863,69.22.154.212
+US,SPOKANE,WA,47.6670,-117.4381,206.104.149.133
+US,KALAMAZOO,MI,42.2663,-85.5617,23.63.227.214
+JP,OSAKA,27,34.67,135.50,72.246.184.89
+US,BURLINGTON,NJ,40.0691,-74.8276,184.26.44.42
+IN,MUMBAI,MH,18.98,72.83,124.124.252.159
+US,SANGABRIEL,CA,34.1144,-118.0896,23.215.15.9
+PT,LISBON,"",38.72,-9.13,92.122.127.109
+US,PALOALTO,CA,37.4439,-122.1504,184.84.180.101
+GB,MANCHESTER,EN,53.50,-2.22,23.67.255.158
+US,LEWISVILLE,TX,33.0463,-96.9939,107.14.43.29
+US,PINELLASPARK,FL,27.8427,-82.6999,63.141.200.248
+US,GRANDJUNCTION,CO,39.0723,-108.5429,184.85.215.165
+US,WYOMING,MI,42.8655,-85.6221,23.67.60.223
+US,ROSEMEAD,CA,34.0646,-118.0833,23.216.10.54
+US,ROCKYRIVER,OH,41.4702,-81.8524,72.247.10.237
+AU,ADELAIDE,SA,-34.93,138.60,23.205.117.14
+DE,BAYREUTH,BY,49.95,11.58,195.145.147.107
+US,QUINCY,WA,47.1872,-119.8129,184.27.45.150
+US,HUNTINGTONPARK,CA,33.9770,-118.2172,184.87.195.109
+US,CARY,NC,35.7524,-78.7781,209.18.41.27
+DE,ESCHBORN,HE,50.13,8.55,92.122.207.179
+US,LYNN,MA,42.4611,-70.947,23.67.244.240
+US,BIXBY,OK,35.9022,-95.8422,23.215.15.22
+AE,DUBAI,"",25.25,55.28,173.223.52.70
+DE,SIEGEN,NW,50.87,8.03,195.145.147.109
+US,PECOS,TX,31.4465,-103.7134,23.74.8.24
+CA,JOLIETTE,QC,46.03,-73.43,67.69.197.95
+US,DENVER,CO,39.7393,-104.9844,23.215.15.32
+CN,SHIJIAZHUANG,HE,38.04,114.48,72.246.191.19
+CN,URUMQI,XJ,43.80,87.58,72.246.191.19
+DE,MUNICH,BY,48.15,11.58,84.53.146.39
+US,SWEDESBORO,NJ,39.7570,-75.3338,72.247.10.237
+US,MEDFORD,MA,42.4184,-71.1069,184.25.109.196
+US,SHREVEPORT,LA,32.5051,-93.7448,96.17.153.157
+DE,AUGSBURG,BY,48.37,10.88,195.145.147.101
+BR,CURITIBA,PR,-25.42,-49.25,189.75.165.189
+US,POMPANOBEACH,FL,26.2349,-80.1201,23.79.240.36
+BR,PORTOALEGRE,RS,-30.03,-51.20,189.75.165.189
+PR,SANJUAN,"",18.4697,-66.1179,23.61.195.163
+BD,DHAKA,"",23.72,90.41,165.254.134.201
+LK,COLOMBO,"",6.93,79.85,23.220.148.146
+US,SANYSIDRO,CA,32.7154,-117.1565,23.220.149.124
+US,IRVINE,CA,33.6880,-117.7988,184.50.26.201
+US,LYNNWOOD,WA,47.8111,-122.2834,184.27.179.159
+US,BAYTOWN,TX,29.7803,-94.894,23.212.53.75
+US,AMARILLO,TX,35.2118,-101.7582,23.5.164.146
+US,MOUNTJULIET,TN,36.1974,-86.4365,23.79.240.36
+US,BAYCITY,MI,43.5968,-83.9583,23.63.227.214
+US,CLEVELAND,OH,41.4995,-81.6959,23.74.8.24
+CA,BRANDON,MB,49.83,-99.95,23.74.8.24
+US,CONYERS,GA,33.7241,-83.9735,23.79.240.36
+US,TAMPA,FL,27.9475,-82.4588,165.254.205.7
+US,LUSBY,MD,38.3848,-76.4416,23.192.161.21
+US,HARRIMAN,TN,35.9599,-84.4439,23.79.240.48
+DE,STUTTGART,BW,48.77,9.18,84.53.146.34
+US,SANMATEO,CA,37.5741,-122.3193,69.22.166.208
+US,WEATHERFORD,TX,32.8532,-97.696,204.93.47.216
+US,RICHMOND,VA,37.5539,-77.4608,63.130.161.140
+BE,BRUSSELS,"",50.83,4.33,23.62.100.152
+US,GROVE,OK,36.5736,-94.7059,23.5.164.143
+US,REDDING,CA,40.4417,-122.9863,23.216.10.54
+US,BLOOMINGTON,IL,40.4766,-88.992,23.67.60.223
+US,SIOUXFALLS,SD,43.5503,-96.7002,107.14.38.217
+US,KILLEEN,TX,31.1169,-97.7264,107.14.43.30
+US,LONGVIEW,WA,46.2098,-123.0644,23.212.59.85
+KZ,ALMATY,"",43.25,76.95,23.14.94.224
+JP,IZUMO,32,35.37,132.77,23.3.74.113
+US,DALTON,GA,34.7698,-84.9703,63.216.54.236
+US,RIVERSIDE,CA,33.9951,-117.3732,23.216.10.54
+US,OXFORD,OH,39.4851,-84.7501,107.14.38.224
+DE,LEIPZIG,SN,51.30,12.33,80.157.150.169
+DE,MAINZ,RP,50.00,8.27,194.25.95.214
+GB,HUDDERSFIELD,EN,53.65,-1.78,88.221.87.94
+NZ,TAURANGA,"",-37.69,176.17,219.88.186.164
+RO,TIMISOARA,"",45.76,21.23,23.212.108.28
+HU,TOROKBALINT,"",47.43,18.92,213.198.95.213
+DE,BAYERN,BY,47.80,12.53,2.16.217.206
+US,FOUNTAINVALLEY,CA,33.7104,-117.9513,107.14.44.185
+US,VISTA,CA,33.1789,-117.2437,63.151.119.16
+US,REYNOLDSBURG,OH,39.9581,-82.7839,23.212.53.75
+US,CHEYENNE,WY,41.1301,-104.8689,69.31.59.63
+US,TUCSON,AZ,32.2167,-110.9709,184.50.26.204
+US,KIRKLAND,WA,47.6755,-122.1871,23.61.195.163
+US,EAGLERIVER,AK,61.1936,-149.321,96.17.108.26
+CO,BOGOTA,"",4.60,-74.08,23.74.2.7
+US,ELPASO,TX,31.7603,-106.4799,107.14.43.29
+US,OMAHA,NE,41.2596,-95.9374,23.74.8.8
+CA,NANAIMO,BC,49.15,-123.92,184.27.179.159
+US,MILPITAS,CA,37.4486,-121.8587,96.17.12.48
+US,NEWHARTFORD,NY,43.0600,-75.2864,107.14.38.227
+UA,UKRAINA,"",47.33,36.27,2.20.142.166
+US,CHARLOTTE,NC,35.2287,-80.8458,63.151.29.15
+US,GARDENGROVE,CA,33.7860,-117.9318,184.50.26.201
+US,APPLETON,WI,44.2816,-88.3849,107.14.38.224
+US,LANCASTER,CA,34.7349,-118.1508,184.50.26.204
+BR,SAOPAULO,SP,-23.53,-46.62,177.159.181.174
+CN,TAIYUAN,SX,37.87,112.56,72.246.191.16
+US,CICERO,IL,41.8443,-87.7585,23.67.60.222
+US,ELKIN,NC,36.3086,-80.843,209.18.41.27
+US,MOUNTVERNON,WA,48.4305,-122.4357,184.27.179.159
+AZ,BAKI,"",40.37,49.88,80.239.149.123
+US,LARAMIE,WY,41.3416,-105.6973,23.212.53.64
+US,ALBANY,OR,44.6313,-123.0676,184.27.179.159
+US,ADDISON,IL,41.9314,-88.011,107.14.38.224
+RU,CHITA,"",52.03,113.55,2.21.240.61
+US,GAMBRILLS,MD,38.9852,-76.6657,23.192.161.30
+US,FAIRFIELD,OH,39.3284,-84.5465,107.14.38.217
+US,BOERNE,TX,29.8239,-98.758,107.14.36.199
+DE,SULZBACH,HE,50.13,8.53,92.122.207.179
+CN,CHANGSHA,HN,28.20,112.97,72.246.191.19
+US,LONGBEACH,CA,33.7668,-118.1886,23.216.10.54
+US,SEARCY,AR,35.2662,-91.8491,96.16.7.101
+NL,AMSTERDAM,"",52.35,4.92,95.100.169.105
+US,HUNTINGTONBEACH,CA,33.7036,-117.9942,23.216.10.78
+CN,JINAN,SD,36.67,117.00,184.50.87.176
+CH,BERN,"",46.92,7.47,193.247.167.211
+US,BILLINGS,MT,45.6311,-108.3519,107.14.32.235
+CL,SANTIAGO,"",-33.45,-70.67,200.91.22.117
+DE,OLDENBURG,NI,53.17,8.20,92.122.207.179
+US,VISALIA,CA,36.2961,-119.382,96.17.12.44
+AU,HOBART,TAS,-42.92,147.33,210.9.88.72
+ET,ADISABEBA,"",9.03,38.70,80.239.237.231
+US,ROCKPORT,TX,28.0205,-97.0545,107.14.43.29
+HK,KOWLOON,"",22.32,114.18,23.76.205.90
+US,CHANDLER,AZ,33.3240,-111.8671,184.50.26.204
+CA,HAMILTON,ON,43.25,-79.83,72.246.43.233
+US,ANCHORAGE,AK,61.2169,-149.8682,165.254.1.206
+HK,HUNGHOM,"",22.30,114.18,23.76.205.111
+JP,NAKANO,14,35.57,139.28,72.246.184.89
+US,MOUNTDORA,FL,28.8027,-81.6446,63.148.206.235
+US,PISCATAWAY,NJ,40.5465,-74.4629,216.151.187.186
+US,LASVEGAS,NV,36.1730,-115.1233,23.61.195.163
+FR,MONTPELLIER,"",43.60,3.88,2.20.243.42
+US,SULLIVAN,MO,38.2643,-91.1348,63.216.54.216
+US,FAIROAKS,CA,38.6525,-121.2544,96.17.12.44
+US,RANCHOCUCAMONGA,CA,34.1370,-117.5982,23.216.10.54
+AF,KABUL,"",34.52,69.18,23.14.94.224
+TT,PORTOFSPAIN,"",10.65,-61.52,204.93.33.141
+DE,BREMEN,HB,53.08,8.80,194.25.95.225
+ZA,JOHANNESBURG,"",-26.20,28.08,41.193.163.53
+US,COACHELLA,CA,33.6820,-116.1678,184.50.26.194
+US,CHAMPAIGN,IL,40.1154,-88.2438,23.67.60.223
+FR,BAYONNE,"",43.48,-1.48,81.52.201.85
+PR,LUQUILLO,"",18.3744,-65.7168,72.246.65.26
+JP,YOKOHAMA,14,35.45,139.65,72.246.191.16
+FR,MARSEILLE,"",43.30,5.40,90.84.50.108
+AU,SUNSHINE,VIC,-37.78,144.83,184.84.221.85
+US,LIVERMORE,CA,37.6209,-121.6768,184.84.180.101
+US,PHILADELPHIA,PA,39.9525,-75.1644,23.67.242.139
+JM,KINGSTON,"",18.00,-76.80,165.254.205.7
+US,BEAVERTON,OR,45.4908,-122.8046,23.212.59.85
+US,ALHAMBRA,CA,34.0905,-118.1279,205.185.195.183
+US,PLEASANTHILL,CA,37.9547,-122.076,96.17.12.48
+US,CUPERTINO,CA,37.3086,-122.0891,96.17.12.44
+US,DAVIS,CA,38.5631,-121.7605,23.61.195.165
+CA,KAMLOOPS,BC,50.67,-120.33,184.27.179.187
+DE,HOYERSWERDA,SN,51.43,14.25,195.95.193.132
+DE,AACHEN,NW,50.77,6.10,80.157.170.158
+IT,PALERMO,"",38.12,13.37,79.140.80.222
+NL,ROTTERDAM,"",51.92,4.50,92.122.189.114
+IL,TELAVIV,"",32.07,34.77,212.25.69.134
+US,CORVALLIS,OR,44.6364,-123.2804,23.212.59.78
+HT,PORTAUPRINCE,"",18.54,-72.33,23.74.2.7
+NO,OSLO,"",59.92,10.75,2.21.240.40
+US,SOUTHFIELD,MI,42.4750,-83.2896,72.247.10.241
+PL,KRAKOW,"",50.08,19.92,88.221.93.150
+US,GILROY,CA,37.0418,-121.4684,23.216.10.54
+US,MINNEAPOLIS,MN,44.9847,-93.2709,23.67.60.223
+US,HICKSVILLE,NY,40.7626,-73.5241,184.26.44.42
+US,BELLEVUE,WA,47.6186,-122.204,23.212.59.85
+US,HYDEPARK,NY,41.8034,-73.8926,184.51.125.79
+SE,VAXJO,G,56.88,14.82,213.155.156.212
+US,LAKELAND,FL,28.0375,-81.9046,23.33.186.101
+US,DUBUQUE,IA,42.5490,-90.6988,23.77.234.35
+US,OAKLANDGARDENS,NY,40.7457,-73.7574,24.143.199.188
+ID,MULIA,"",-2.33,106.27,23.0.162.21
+US,DAVENPORT,IA,41.5221,-90.5751,107.14.38.217
+FR,NANCY,"",48.68,6.20,81.52.201.85
+AU,NORTHSYDNEY,NSW,-33.84,151.21,210.11.142.64
+US,AURORA,IL,41.7671,-88.2508,23.67.60.217
+DE,ERFURT,TH,50.98,11.03,80.157.150.201
+US,APOPKA,FL,28.6645,-81.5402,23.33.186.101
+US,WOODBURY,NJ,39.8266,-75.1276,184.26.44.42
+CA,FREDERICTON,NB,45.95,-66.63,2.20.142.166
+GR,THESSALONIKI,"",40.63,22.93,2.16.217.206
+US,ATHENS,OH,39.3095,-82.081,107.14.38.217
+US,CHESTERTOWN,MD,39.2007,-76.1457,168.143.243.37
+GT,GUATEMALACITY,"",14.63,-90.52,72.246.65.38
+US,PURCHASE,NY,41.0397,-73.7118,69.31.77.208
+US,TRACY,CA,37.7546,-121.3694,23.61.195.163
+US,HEWITT,TX,31.4546,-97.1957,184.26.93.116
+US,LUFKIN,TX,31.3301,-94.744,64.86.135.210
+AT,VIENNA,"",48.20,16.37,195.145.147.108
+US,PLEASANTON,CA,37.6395,-121.8586,23.215.15.22
+US,ELKO,NV,40.8858,-115.7034,23.74.8.8
+US,ARLINGTON,TX,32.6288,-97.1183,184.28.23.4
+US,VICTORVILLE,CA,34.5003,-117.3379,23.216.10.54
+US,FULLERTON,CA,33.8793,-117.8962,184.50.26.179
+US,FORTSMITH,AR,35.3642,-94.4158,23.215.15.22
+PR,AGUADILLA,"",18.4409,-67.1508,23.33.186.101
+US,TEMPLECITY,CA,34.1016,-118.0554,23.216.10.54
+FR,CHAUMONT,"",49.27,1.88,2.16.117.200
+US,WAUKEGAN,IL,42.3639,-87.8447,23.212.53.64
+US,SUNCITY,AZ,33.6050,-112.2837,184.50.26.179
+US,CUMMING,GA,34.2093,-84.1423,72.246.247.5
+US,INDIO,CA,33.7269,-116.2361,184.50.26.179
+US,BAKERSFIELD,CA,35.3841,-119.0207,184.26.93.111
+US,MALIBU,CA,34.0402,-118.6328,173.223.52.70
+DE,BADEN,BW,48.75,8.25,2.16.217.206
+US,RUCKERSVILLE,VA,38.2469,-78.3926,184.26.44.42
+CN,HANGZHOU,ZJ,30.26,120.17,23.76.205.90
+US,BOSSIERCITY,LA,32.5785,-93.6897,23.5.164.146
+DE,HANNOVER,NI,52.37,9.72,80.157.170.154
+US,DENISON,TX,33.7390,-96.5197,23.215.15.22
+US,CLIFTON,NJ,40.8800,-74.1446,184.26.44.42
+US,HONOLULU,HI,21.3069,-157.8584,23.212.53.75
+US,LODI,CA,38.1161,-121.1069,23.212.52.79
+CA,SASKATOON,SK,52.13,-106.67,205.185.195.183
+US,TUSCALOOSA,AL,33.1664,-87.6118,205.185.205.102
+US,MOBILE,AL,30.6945,-88.0431,65.120.60.228
+IN,SURAT,GJ,21.17,72.83,23.57.69.156
+US,SAINTMARYS,GA,30.7777,-81.5701,184.51.35.215
+DE,GOTTINGEN,NI,51.53,9.93,194.25.95.225
+US,AUGUSTA,GA,33.4341,-81.956,23.79.240.36
+US,SANMARCOS,CA,33.1507,-117.1748,184.50.26.204
+SE,ARJEPLOG,BD,66.05,17.90,213.155.156.212
+GB,MILTONKEYNES,EN,52.03,-0.70,92.122.54.12
+JP,NIHONBASHIGOFUKUBASHI,13,35.68,139.77,23.61.250.113
+US,NORTHHILLS,CA,34.2386,-118.4807,184.50.26.194
+US,MESA,AZ,33.4340,-111.8483,63.226.34.173
+TR,ISTANBUL,"",41.02,28.96,2.16.217.211
+US,WILBURTON,OK,34.8806,-95.3086,23.215.15.9
+DE,SAARBRUCKEN,SL,49.23,7.00,194.25.95.212
+RO,ALBAIULIA,"",45.07,28.53,88.221.93.150
+US,WESTCOVINA,CA,34.0668,-117.9376,23.216.10.54
+IN,ROHTAK,HR,28.90,76.57,124.124.252.153
+PK,KARACHI,"",24.87,67.05,23.5.165.167
+IN,HARYANA,HR,29.62,76.98,96.17.182.136
+AU,ROSEDALE,VIC,-38.15,146.78,23.62.157.32
+MY,SHAHALAM,"",3.08,101.53,23.198.99.130
+US,HOLLYWOOD,FL,26.0478,-80.1254,23.79.240.36
+US,ALTON,IL,38.9395,-90.1236,96.17.14.16
+BG,SEVLIEVO,"",43.02,25.10,2.20.45.102
+PH,QUEZONCITY,"",14.63,121.03,202.78.83.170
+GB,ILFORD,EN,51.55,0.05,23.3.15.22
+US,HUNTINGTON,WV,38.3693,-82.4123,184.26.44.42
+US,CARLSBAD,CA,33.1500,-117.3007,184.50.26.189
+US,GARNER,NC,35.6418,-78.5748,96.16.12.216
+RU,URAL,"",54.11,38.33,213.155.156.208
+RU,VOLGOGRAD,"",48.80,44.59,80.239.217.238
+AU,NORTHRYDE,NSW,-33.82,151.10,23.62.224.60
+US,NEWLENOX,IL,41.5052,-87.9609,23.74.8.24
+US,VENICE,CA,33.9944,-118.4634,184.27.45.150
+US,STOCKTON,CA,37.9578,-121.2897,96.17.12.44
+US,AZUSA,CA,34.1312,-117.9157,23.216.10.78
+US,ESCONDIDO,CA,33.0829,-117.0241,23.216.10.54
+MT,VALLETTA,"",35.90,14.51,77.67.29.109
+KR,YONGDONG,"",36.92,126.98,23.65.188.30
+US,BRONX,NY,40.8208,-73.9235,184.51.125.79
+IN,ANDRA,AP,18.35,83.20,80.239.237.231
+CN,WUHAN,HB,30.58,114.27,117.103.188.218
+CA,PARKSVILLE,BC,49.30,-124.32,184.27.179.181
+DE,PADERBORN,NW,51.72,8.77,195.145.147.101
+GB,LEICESTER,EN,52.63,-1.13,184.27.139.24
+JP,OTEMACHI,13,35.68,139.77,72.246.191.19
+US,ROSAMOND,CA,34.8931,-118.3533,23.216.10.78
+US,EUGENE,OR,44.0685,-123.082,206.104.149.133
+US,SNOQUALMIE,WA,47.5717,-121.7785,206.104.149.146
+CN,HEFEI,AH,31.86,117.28,72.246.191.19
+IN,NAGORE,TN,10.82,79.85,117.239.240.96
+US,ROSWELL,NM,33.4293,-104.519,65.116.149.89
+DE,GOERLITZ,SN,51.17,15.00,195.95.193.147
+US,WAUPACA,WI,44.3534,-89.1229,23.63.227.227
+US,MURFREESBORO,TN,35.7571,-86.3959,23.79.240.36
+IN,PUNE,MH,18.53,73.87,23.57.69.159
+IQ,BAGHDAD,"",33.34,44.39,195.27.155.188
+QA,DOHA,"",25.29,51.53,82.148.111.135
+US,JERSEYCITY,NJ,40.7286,-74.0775,23.61.195.165
+US,LITTLEROCK,AR,34.7467,-92.2799,184.84.180.101
+US,EVERGREEN,AL,31.4945,-86.9123,184.51.35.226
+US,DANVILLE,VA,36.6603,-79.4863,184.27.45.150
+FR,PUTEAUX,"",48.87,2.23,23.200.87.59
+US,YUBACITY,CA,39.0204,-121.6141,23.212.52.88
+TR,KOCA,"",41.68,32.48,92.122.215.67
+US,BALDWINPARK,CA,34.0941,-117.9709,184.27.45.150
+US,SANTAMONICA,CA,34.0153,-118.4926,23.216.10.78
+US,MARION,MA,41.7087,-70.7664,184.25.109.213
+CN,CHENGDU,SC,30.67,104.07,72.246.191.16
+US,LAWNDALE,CA,33.8885,-118.3514,184.50.26.204
+US,MEAD,CO,40.2553,-104.9897,23.215.15.9
+US,BLYTHE,CA,33.5664,-114.6283,24.143.194.216
+US,LINCOLN,NE,40.8000,-96.6664,184.26.93.116
+US,ANTIOCH,CA,37.9799,-121.8022,23.212.52.79
+AT,AINET,"",46.87,12.70,23.62.237.133
+KZ,ASTANA,"",51.17,71.50,80.239.222.167
+US,BIGRAPIDS,MI,43.6800,-85.5606,23.63.227.214
+HR,ZAGREB,"",45.80,16.00,23.14.94.220
+US,BRIGHAMCITY,UT,41.4833,-112.0954,184.84.180.98
+GB,KNOWSLEY,EN,53.45,-2.85,88.221.87.112
+FI,SAUNALAHTI,"",63.22,28.55,193.184.164.239
+NZ,PORIRUA,"",-41.13,174.85,219.88.186.172
+PH,MANILA,"",14.58,121.00,202.78.83.170
+DE,DORTMUND,NW,51.52,7.45,80.157.170.158
+US,ELKCITY,OK,35.4257,-99.4694,23.215.15.32
+US,MEMPHIS,TN,35.1496,-90.0487,23.220.100.224
+US,WINTERPARK,FL,28.5987,-81.3537,209.170.117.178
+US,NEWORLEANS,LA,29.9574,-90.0769,23.215.15.22
+US,CATHEDRALCITY,CA,33.8234,-116.4603,184.50.26.194
+FR,ROUEN,"",49.43,1.08,2.20.243.45
+US,PALMCOAST,FL,29.4748,-81.1274,23.33.186.101
+CH,BIEL,"",47.17,7.25,193.247.167.214
+UA,ODESA,"",46.47,30.73,80.239.149.123
+US,ELKGROVEVILLAGE,IL,42.0131,-87.9972,23.220.148.122
+US,RICHARDSON,TX,32.9743,-96.7425,107.14.36.200
+US,COCOABEACH,FL,28.3302,-80.6145,23.33.186.134
+US,SANTABARBARA,CA,34.4179,-119.711,184.50.26.204
+US,SHERWOOD,OR,45.3505,-122.8661,184.27.179.181
+US,HAYWARD,CA,37.6687,-122.0799,23.212.52.82
+CN,GUIYANG,GZ,26.58,106.72,23.76.205.111
+RU,NOVOSIBIRSK,"",55.03,82.92,2.21.240.61
+US,CLOVIS,CA,36.8770,-119.5829,96.17.12.48
+MX,HERMOSILLO,SON,29.07,-110.97,173.223.52.67
+US,LAKEHAVASUCITY,AZ,34.6022,-113.772,24.143.194.180
+US,DOWNEY,CA,33.9400,-118.1319,184.50.26.179
+US,MANSFIELD,OH,40.7584,-82.5156,205.185.195.170
+MV,MALE,"",4.17,73.50,96.17.182.136
+US,MURRIETA,CA,33.5484,-117.2689,23.216.10.54
+US,IRMO,SC,34.1400,-81.2028,72.246.247.5
+US,COSTAMESA,CA,33.6791,-117.9087,184.50.26.201
+US,TOMBALL,TX,30.0721,-95.6453,96.17.163.165
+US,BELLINGHAM,WA,48.7531,-122.5024,184.27.179.179
+US,GARDENA,CA,33.8912,-118.2972,184.50.26.201
+DE,KOBLENZ,RP,50.35,7.60,194.25.95.212
+US,KIRKSVILLE,MO,40.1490,-92.6667,107.14.43.30
+US,WICHITAFALLS,TX,33.9834,-98.4403,184.28.23.24
+JP,HODOGAYA,14,35.45,139.60,117.104.139.162
+HR,SPLIT,"",43.51,16.46,46.33.70.97
+US,TURLOCK,CA,37.4741,-120.8695,23.216.10.54
+CA,ETOBICOKE,ON,43.70,-79.57,209.148.192.57
+US,JOLIET,IL,41.5083,-88.2276,23.67.60.223
+US,SOUTHJORDAN,UT,40.5586,-111.9523,23.215.15.32
+US,TUJUNGA,CA,34.3190,-118.2411,184.50.26.179
+FR,AUBERVILLIERS,"",48.92,2.38,2.20.243.42
+FI,HELSINKI,"",60.18,24.93,80.239.237.84
+US,OCEANSIDE,CA,33.1959,-117.3789,63.233.112.196
+US,CASTAIC,CA,34.4864,-118.5786,184.50.26.204
+US,GROTON,CT,41.3595,-72.0439,72.247.10.237
+US,COLLINSVILLE,IL,38.6902,-89.9816,96.17.14.16
+US,ALBUQUERQUE,NM,35.0846,-106.6516,184.84.180.101
+MX,CIUDADJUAREZ,CHH,19.07,-103.88,23.215.15.22
+US,WOODBRIDGE,VA,38.6245,-77.2692,184.28.17.55
+US,VEROBEACH,FL,27.6406,-80.4018,184.28.184.16
+US,HIGHLAND,CA,34.1353,-117.1532,23.216.10.78
+ES,BARCELONA,"",41.38,2.18,213.248.113.93
+US,HARTSELLE,AL,34.4480,-86.8894,23.220.100.223
+EG,CAIRO,"",30.05,31.25,79.140.94.243
+US,BIGSTONEGAP,VA,36.8453,-82.7571,23.212.53.64
+US,WALNUTCREEK,CA,37.8720,-122.0686,23.212.52.82
+CA,KELOWNA,BC,49.90,-119.48,184.27.179.187
+US,THOMASTON,GA,32.8808,-84.3396,23.79.240.36
+DE,MEERBUSCH,NW,51.28,6.67,2.22.61.102
+NO,FORNEBU,"",59.90,10.63,2.21.240.40
+FR,STRASBOURG,"",48.58,7.75,77.67.27.231
+US,ANNARBOR,MI,42.2601,-83.8448,23.63.227.214
+US,ALLEN,TX,33.0968,-96.6341,96.16.7.120
+US,COVINGTON,LA,30.4598,-90.1271,96.17.153.157
+SE,UPPSALA,C,59.85,17.63,80.239.237.93
+MX,MONTERREY,NLE,25.67,-100.32,23.215.15.22
+US,ORANGE,CA,33.7878,-117.8523,184.50.26.179
+JP,SOKA,11,35.82,139.81,117.104.139.136
+GU,HAGATNA,"",13.4744,144.7478,64.145.95.145
+US,BOSTON,MA,42.3581,-71.0647,23.67.244.224
+US,REDONDOBEACH,CA,33.8305,-118.3842,184.50.26.192
+AU,BURNIE,TAS,-41.07,145.92,202.7.177.76
+US,MAMMOTHLAKES,CA,37.6599,-118.912,23.216.10.54
+US,KENNEWICK,WA,46.2117,-119.1733,23.61.195.165
+DE,CHEMNITZ,SN,50.83,12.92,194.25.95.214
+AD,ANDORRA,"",42.50,1.52,80.149.168.114
+US,SANFORD,FL,28.8131,-81.3279,23.34.56.142
+US,LAKEVILLE,CT,41.9547,-73.4419,165.254.202.92
+US,AKRON,OH,41.0433,-81.5239,107.14.38.218
+AU,FERNTREEGULLY,VIC,-37.88,145.30,184.84.221.116
+US,AUDUBON,NJ,39.8910,-75.0738,23.67.60.223
+DE,NURNBERG,BY,49.45,11.07,195.145.147.108
+US,EAUCLAIRE,WI,44.7381,-91.5038,184.85.215.165
+US,CONWAY,AR,35.0822,-92.366,96.16.7.120
+US,EASTSYRACUSE,NY,43.1073,-76.0418,107.14.38.218
+US,OZONEPARK,NY,40.6844,-73.8499,184.26.44.42
+FR,VILLARDBONNOT,"",45.23,5.88,2.16.117.200
+US,COLUMBUS,OH,40.0994,-83.0166,107.14.38.217
+US,PLATTEVILLE,WI,42.7466,-90.4931,63.151.29.15
+US,WAKEFOREST,NC,35.9666,-78.5355,209.18.41.27
+NZ,WELLINGTON,"",-41.30,174.78,219.88.186.167
+HR,CORE,"",45.09,16.33,23.14.94.228
+KH,PHNOMPENH,"",11.55,104.92,23.76.205.111
+US,SAHUARITA,AZ,31.9776,-110.9216,23.215.15.22
+JP,HAMAMATSU,22,34.70,137.73,117.104.138.235
+US,LIVINGSTON,NJ,40.7857,-74.3293,23.67.242.156
+US,HEMET,CA,33.6979,-116.9786,184.27.45.157
+US,PUEBLO,CO,38.2964,-104.5387,184.84.180.68
+US,ELMONTE,CA,34.0769,-118.0327,184.50.26.201
+US,CHESTERFIELD,MO,38.6405,-90.6464,63.216.54.216
+GB,UDDINGSTON,SC,55.80,-4.07,88.221.87.94
+US,BABYLON,NY,40.6311,-73.3431,184.26.44.38
+DE,KASSEL,HE,51.32,9.50,194.25.95.225
+US,GRANADAHILLS,CA,34.2913,-118.506,184.27.45.157
+DE,DREIEICH,HE,50.00,8.70,92.122.215.89
+US,MANTECA,CA,37.8341,-121.2013,23.212.52.79
+PL,KATOWICE,"",50.27,19.02,95.101.2.112
+US,MCKEE,KY,37.4446,-84.0227,23.63.227.227
+US,WESTWARWICK,RI,41.7000,-71.516,72.247.10.241
+US,ENDICOTT,NY,42.1332,-76.0798,107.14.38.227
+ID,DENPASAR,"",-8.65,115.22,23.0.162.46
+RU,VOLOGDA,"",59.22,39.90,2.21.240.40
+US,MIDLOTHIAN,VA,37.4373,-77.6622,63.130.161.140
+US,BRECKSVILLE,OH,41.3049,-81.6177,96.17.9.14
+US,AMHERST,MA,42.3773,-72.4671,165.254.35.197
+US,SANLUISOBISPO,CA,35.2383,-120.6214,23.216.10.78
+US,NEWHOLLAND,PA,40.1038,-76.0725,184.27.45.150
+US,GILBERT,AZ,33.3504,-111.8085,184.50.26.203
+US,SYOSSET,NY,40.8243,-73.4974,165.254.35.182
+US,PACIFICA,CA,37.6009,-122.4839,173.223.52.70
+RU,AKTAY,"",55.82,46.78,92.122.215.67
+US,AUBREY,TX,33.2863,-96.9901,184.28.23.24
+US,ROMA,TX,26.5818,-98.985,184.26.93.116
+US,FORTMYERS,FL,26.6175,-81.8713,23.79.240.36
+US,WINSTONSALEM,NC,36.1131,-80.1983,184.27.45.157
+US,BUCKEYE,AZ,33.2239,-112.8563,184.50.26.203
+US,MIDDLETOWN,PA,40.1873,-76.6948,23.192.161.21
+US,BOWIE,MD,38.9862,-76.7389,23.192.161.21
+DE,NETZE,HE,51.22,9.10,23.14.94.224
+UA,DNIPROPETROVSK,"",48.45,34.98,23.14.94.224
+MY,SEMENYIH,"",2.95,101.85,203.106.85.195
+US,GAITHERSBURG,MD,39.1382,-77.1868,184.27.45.157
+US,MISSIONVIEJO,CA,33.6002,-117.6711,2.20.142.166
+US,CENTERVILLE,IA,40.7100,-92.9234,63.216.54.229
+US,MONEE,IL,41.4121,-87.7808,23.67.60.220
+US,CLINTON,MD,38.7501,-76.9068,184.27.45.150
+TR,IZMIR,"",38.42,27.15,193.45.15.198
+KZ,ATYRAU,"",47.12,51.88,23.14.94.228
+US,BINGHAMTON,NY,42.1934,-75.8849,107.14.38.227
+DE,HOST,NW,51.65,6.18,92.122.215.89
+US,PORTOLAVALLEY,CA,37.3686,-122.2154,184.85.249.6
+RU,ROSTOVONDON,"",47.24,39.71,2.21.240.40
+US,PARKER,CO,39.5027,-104.7087,184.84.180.101
+US,HOLLISTER,CA,36.7975,-121.2316,96.17.12.44
+CN,WENZHOU,ZJ,28.02,120.65,72.246.191.19
+US,ANAHEIM,CA,33.8444,-117.9519,184.50.26.179
+US,CASTROVALLEY,CA,37.7052,-122.0821,23.212.52.79
+US,BERKELEY,CA,37.8718,-122.2718,23.61.195.163
+US,KATY,TX,29.8394,-95.7377,23.212.53.64
+IR,GOSTAR,"",35.47,48.88,23.215.60.48
+RU,NOVGOROD,"",58.52,31.28,213.155.156.208
+US,BLACKSBURG,VA,37.2556,-80.429,65.121.209.133
+RU,KRASNODAR,"",45.03,38.98,2.21.240.40
+LT,PANEVEZYS,"",55.73,24.35,92.122.189.114
+GB,SOUTHBANK,EN,54.57,-1.15,173.222.211.203
+US,WELLSBORO,PA,41.7308,-77.349,184.27.45.157
+US,RIVERDALE,GA,33.5562,-84.3998,72.246.247.5
+VN,HOCHIMINHCITY,"",10.75,106.67,23.5.165.168
+US,HERNDON,VA,38.9807,-77.3799,184.27.45.157
+US,INGLEWOOD,CA,33.9563,-118.3585,184.50.26.194
+US,PICKERINGTON,OH,39.9019,-82.7452,96.17.9.8
+US,GRENADA,MS,33.8096,-89.8042,96.17.153.162
+US,RANCHOSANTAMARGARITA,CA,33.6340,-117.6061,23.215.15.22
+SV,SANSALVADOR,"",13.70,-89.20,72.246.65.23
+CZ,PRAGUE,"",50.08,14.47,23.62.237.138
+IM,DOUGLAS,"",54.15,-4.48,195.245.125.249
+FR,NANTES,"",47.22,-1.55,81.52.201.101
+US,BLYTHEVILLE,AR,35.9221,-89.9037,65.113.249.11
+RO,GHEORGHENI,"",46.72,25.62,88.221.93.150
+US,CORONA,CA,33.8754,-117.5659,165.254.51.142
+TZ,ARUSHA,"",-3.37,36.68,41.193.163.45
+JP,KYOWA,01,43.82,144.02,72.246.184.81
+US,MENDOTA,MN,44.8871,-93.1617,63.151.29.15
+US,ALSIP,IL,41.6719,-87.7294,23.67.60.223
+US,SPARTANBURG,SC,34.9341,-82.0149,23.79.240.36
+US,CANTON,GA,34.2348,-84.4442,63.216.54.229
+MY,CYBERJAYA,"",2.97,101.58,23.15.10.91
+US,MORRISTOWN,TN,36.1752,-83.2659,64.86.201.118
+US,MONSON,MA,42.0890,-72.3226,184.25.109.200
+BA,SRPSKA,"",44.81,18.30,23.62.237.133
+US,TRENTON,NJ,40.2167,-74.7433,184.26.44.42
+RO,BUCHAREST,"",44.43,26.10,92.122.215.67
+US,WHITTIER,CA,34.0076,-118.0335,23.216.10.78
+US,MADISONVILLE,KY,37.3245,-87.464,107.14.38.227
+US,AZLE,TX,32.9120,-97.556,23.215.15.22
+IN,BHIWANDI,MH,19.30,73.07,23.57.69.159
+US,BRENTWOOD,TN,36.0347,-86.7836,23.220.100.224
+US,LORAIN,OH,41.4482,-82.1803,107.14.38.227
+US,PINOLE,CA,37.9896,-122.2692,23.61.195.166
+AT,GRAZ,"",47.07,15.45,195.145.147.108
+ID,TANGERANG,"",-6.18,106.62,23.0.162.46
+US,HUMBLE,TX,29.9987,-95.2618,23.212.53.75
+US,ATLANTICBEACH,FL,30.3485,-81.4173,23.79.240.37
+US,BRIDGEPORT,CT,41.1667,-73.2054,184.51.125.79
+US,WARRIOR,AL,33.8170,-86.8457,23.220.100.224
+SE,MALMO,M,55.60,13.00,213.155.156.206
+DE,KAISERSLAUTERN,RP,49.45,7.75,194.25.95.212
+US,FALLBROOK,CA,33.3988,-117.2649,165.254.138.165
+US,IDAHOFALLS,ID,43.4980,-111.7302,192.80.13.117
+SE,LILJEHOLMEN,AB,59.32,18.02,213.155.156.207
+FR,BERGERAC,"",44.85,0.48,92.122.189.114
+US,SMITHTOWN,NY,40.8527,-73.2109,23.67.242.139
+US,PALMSPRINGS,CA,33.8563,-116.5712,184.50.26.194
+DE,BAMBERG,BY,49.87,10.87,194.25.95.214
+AU,ROCHEDALE,QLD,-27.57,153.13,104.72.70.95
+RU,ROSTOV,"",57.19,39.42,217.212.227.31
+US,RAINSVILLE,AL,34.5004,-85.8413,64.86.201.121
+HK,KWUNTONG,"",22.32,114.22,23.76.205.111
+US,SANANGELO,TX,31.5873,-100.522,23.5.164.146
+HK,KWAICHUNG,"",22.35,114.13,23.76.205.90
+US,VIDOR,TX,30.1707,-94.0082,107.14.43.30
+US,GRANDPRAIRIE,TX,32.7740,-97.0052,184.26.93.111
+US,GREATFALLS,MT,47.5115,-111.2723,184.27.179.181
+US,PERRIS,CA,33.7921,-117.3085,184.50.26.201
+US,PLACENTIA,CA,33.8804,-117.8555,23.220.149.114
+US,CHINOHILLS,CA,33.9508,-117.7322,23.216.10.78
+US,MONTGOMERY,AL,32.3667,-86.3002,23.79.240.37
+MX,TIJUANA,BCN,32.53,-117.02,165.254.144.32
+US,FLUSHING,NY,40.7553,-73.8268,24.143.199.188
+VE,CARACAS,"",10.50,-66.92,72.246.65.37
+US,FREDERICK,MD,39.4393,-77.3428,23.192.161.16
+US,WESTPLAINS,MO,36.7256,-91.9123,107.14.38.218
+US,PIOCHE,NV,38.2635,-114.484,23.216.10.78
+US,LEAGUECITY,TX,29.4885,-95.1021,23.212.53.75
+CN,ZHENGZHOU,HA,34.76,113.65,23.76.205.90
+DE,NORDERSTEDT,SH,53.70,10.02,92.122.207.164
+US,LIVONIA,MI,42.3684,-83.3717,69.22.154.219
+US,PORTORANGE,FL,29.2107,-81.0232,184.51.145.22
+US,ROGERS,AR,36.3725,-94.0691,23.215.15.32
+DE,SAARLOUIS,SL,49.32,6.75,2.20.142.166
+BE,ANTWERP,"",51.22,4.42,23.62.100.152
+US,BURBANK,CA,34.2040,-118.3029,184.50.26.201
+CN,SHANGHAI,SH,31.22,121.46,184.50.87.176
+US,MIDLAND,MI,43.5802,-84.3509,23.63.227.214
+US,ONEIDA,NY,43.0606,-75.6518,107.14.38.227
+US,ROYALOAK,MI,42.4907,-83.1379,69.22.154.215
+US,ROANOKE,TX,32.9960,-97.2275,184.28.23.4
+PE,LIMA,"",-12.05,-77.05,200.60.190.82
+US,WESTLAKEVILLAGE,CA,34.1707,-118.8364,184.50.26.203
+CA,WINNIPEG,MB,49.88,-97.17,23.74.8.24
+US,SAINTPAUL,MN,44.9661,-93.0837,63.151.29.12
+US,BUENAPARK,CA,33.8459,-118.0114,107.14.44.212
+US,COLTON,CA,34.0027,-117.2405,184.87.195.99
+GB,ACTON,EN,51.50,-0.25,23.67.255.158
+DE,ROLAND,NW,51.77,8.00,95.101.2.122
+PK,ISLAMABAD,"",33.70,73.17,79.140.94.234
+US,CAMARILLO,CA,34.2276,-119.0699,23.61.195.163
+US,MARYSVILLE,WA,48.0544,-122.1499,184.84.180.98
+RU,PETROZAVODSK,"",61.82,34.33,2.21.240.61
+US,SANLEANDRO,CA,37.7164,-122.1648,96.17.12.44
+US,WALDORF,MD,38.6041,-76.8335,23.192.161.16
+US,NANUET,NY,41.0984,-74.0095,184.26.44.40
+DE,MANNHEIM,BW,49.49,8.46,80.239.237.231
+US,SAINTJAMES,NY,40.8903,-73.169,184.26.44.42
+US,SANBRUNO,CA,37.6225,-122.4186,216.246.93.44
+DE,FREIBURG,BW,48.00,7.85,80.157.150.201
+GR,IRAKLEIO,"",35.33,25.13,23.14.94.220
+FR,GIGNY,"",48.60,4.57,2.16.117.200
+DE,BREMERHAVEN,HB,53.55,8.58,80.157.150.197
+US,NORTHBERGEN,NJ,40.7933,-74.0263,184.51.125.79
+DE,KREFELD,NW,51.33,6.57,80.157.170.154
+US,PLACERVILLE,CA,38.7308,-120.774,23.212.52.88
+US,PROVIDENCE,RI,41.8238,-71.4133,165.254.35.197
+US,NORTHBRUNSWICK,NJ,40.4497,-74.482,184.51.125.68
+US,CARSON,CA,33.8231,-118.267,184.50.26.194
+US,SECAUCUS,NJ,40.7808,-74.0651,204.94.155.231
+US,CINCINNATI,OH,39.1616,-84.4569,23.74.8.8
+US,PORTSMOUTH,VA,36.8107,-76.3702,23.220.148.108
+US,SPRING,TX,30.0613,-95.3841,23.212.53.75
+CY,NICOSIA,"",35.17,33.37,92.122.215.89
+US,ELKRIDGE,MD,39.0285,-76.7125,184.28.17.76
+US,KISSIMMEE,FL,28.3074,-81.4274,23.34.56.142
+US,BATTLECREEK,MI,42.3247,-85.0949,23.67.60.223
+US,FORTLAUDERDALE,FL,26.1210,-80.1281,23.79.240.36
+US,WESTLAFAYETTE,IN,40.4858,-86.9802,23.63.227.214
+CA,CHATHAM,ON,42.40,-82.18,72.246.43.215
+DE,SINGEN,BW,48.97,8.57,2.16.217.211
+CN,NANJING,JS,32.06,118.78,117.103.188.218
+US,EVANSTON,IL,42.0566,-87.6974,107.14.38.217
+US,LANDER,WY,42.6143,-108.5863,23.63.227.214
+US,MICHIGANCITY,IN,41.6870,-86.8677,23.67.60.220
+US,FAYETTEVILLE,AR,35.9902,-94.083,23.77.234.35
+RU,SERPUKHOV,"",54.92,37.41,2.21.240.61
+US,WESTRICHLAND,WA,46.3012,-119.3697,184.27.179.159
+RU,YOSHKAROLA,"",56.64,47.87,80.239.237.80
+RU,SETI,"",53.36,34.21,217.212.227.25
+US,INDIANA,PA,40.6222,-79.1593,184.28.17.55
+US,LAWTON,OK,34.5483,-98.2849,184.28.23.4
+US,MIAMIBEACH,FL,25.7928,-80.3138,165.254.205.13
+CA,VICTORIA,BC,48.43,-123.35,165.254.35.197
+US,HENDERSONVILLE,NC,35.2687,-82.5413,184.51.35.226
+FR,LADEFENSE,"",48.90,2.23,90.84.50.204
+DE,BOCHUM,NW,51.48,7.22,194.25.95.219
+DO,SANTODOMINGO,"",18.47,-69.90,72.246.65.38
+US,MILLINGTON,MI,43.2680,-83.543,23.74.8.24
+US,LASALLE,IL,41.3955,-89.0957,23.67.60.223
+PL,POZNAN,"",52.42,16.97,2.22.52.105
+AU,THOMASTOWN,VIC,-37.68,145.02,23.62.8.21
+US,FRANKFORT,IL,41.4748,-87.8351,23.67.60.222
+BA,MOSTAR,"",43.34,17.81,77.67.29.109
+US,OKLAHOMACITY,OK,35.4678,-97.5164,23.215.15.22
+US,HAWTHORNE,CA,33.9143,-118.3494,184.87.195.99
+US,OLATHE,KS,38.8815,-94.8187,23.67.60.222
+SA,JEDDAH,"",21.52,39.22,79.140.94.234
+US,BURLESON,TX,32.5215,-97.3032,96.16.7.120
+US,PANORAMACITY,CA,34.2243,-118.4446,184.50.26.179
+US,WADSWORTH,OH,41.0524,-81.7404,184.27.45.157
+DE,ULM,BW,48.40,10.00,80.157.150.192
+JP,MORIOKA,03,39.70,141.15,96.7.251.97
+US,NAPLES,FL,26.1418,-81.795,23.79.240.37
+CN,TIANJIN,TJ,39.14,117.18,184.50.87.178
+US,WESTJORDAN,UT,40.6225,-111.9765,184.84.180.68
+US,KELLER,TX,32.9347,-97.2515,23.5.164.146
+US,GRESHAM,OR,45.5092,-122.431,23.212.59.63
+US,FALLSCHURCH,VA,38.8669,-77.1528,23.220.148.108
+US,STERLING,MI,44.0665,-84.046,23.67.60.217
+US,ENGLEWOOD,CO,39.6440,-104.9826,184.84.180.92
+US,GENEVA,NY,42.8475,-77.0198,107.14.38.224
+US,PALMBAY,FL,28.0264,-80.6045,23.33.186.134
+US,WESTFIELD,MA,42.1558,-72.7734,23.74.8.24
+US,PICORIVERA,CA,33.9895,-118.0913,184.50.26.201
+US,CHAMBERSBURG,PA,39.9438,-77.6827,23.192.161.16
+US,RUSTON,LA,32.5075,-92.6828,23.5.164.146
+US,WALLINGFORD,PA,39.8901,-75.3702,184.26.44.42
+US,REDLANDS,CA,34.0057,-117.1506,184.50.26.201
+US,WENATCHEE,WA,47.3635,-120.3481,184.27.179.187
+US,WILLITS,CA,39.4525,-123.3878,184.84.180.98
+CA,KITCHENER,ON,43.45,-80.50,72.246.43.233
+US,RIALTO,CA,34.1109,-117.3774,184.87.195.109
+JP,SHIZUOKA,22,34.97,138.38,72.246.191.16
+US,MARYVILLE,TN,35.7829,-83.8797,184.28.127.55
+US,SEASIDE,CA,36.6221,-121.8217,96.17.12.44
+IN,ANANDNAGAR,UP,27.10,83.28,124.124.252.153
+US,WASILLA,AK,61.5827,-149.4056,96.17.108.26
+US,VANNUYS,CA,34.1781,-118.4316,107.14.44.185
+RU,VLADIKAVKAZ,"",43.04,44.68,96.7.251.95
+MC,MONACO,"",43.73,7.42,2.22.49.28
+US,MCMINNVILLE,OR,45.1977,-123.2704,184.27.179.159
+GB,SOUTHAMPTON,EN,50.90,-1.40,184.27.45.157
+CN,CHANGCHUN,JL,43.89,125.32,72.246.190.189
+RU,KRASNOYARSK,"",56.01,92.79,2.21.240.61
+DE,GIESSEN,HE,50.58,8.65,194.25.95.214
+US,ELCAJON,CA,32.7856,-116.8874,184.50.26.204
+US,WINDSOR,CO,40.4952,-104.8788,173.197.194.159
+US,AUBURNHILLS,MI,42.6398,-83.2944,23.67.60.223
+US,JUSTICE,IL,41.7509,-87.8345,23.67.60.223
+US,IRVING,TX,32.8139,-96.9488,23.215.15.32
+GU,TAMUNING,"",13.4839,144.7769,165.254.96.242
+ZA,DURBAN,"",-29.85,31.02,195.245.125.249
+US,CRANBURY,NJ,40.3132,-74.5206,23.67.60.222
+US,GRANDRAPIDS,MI,42.9634,-85.6681,23.67.60.223
+US,RAYMORE,MO,38.7996,-94.4429,23.67.60.222
+US,PLANO,TX,33.0562,-96.7336,107.14.36.200
+US,EASTLANSING,MI,42.7547,-84.4613,165.254.207.111
+BH,ALMANAMAH,"",26.24,50.58,2.20.249.5
+US,WHITEMARSH,MD,39.3909,-76.4042,23.192.161.21
+US,PADUCAH,KY,37.0331,-88.716,23.220.100.223
+DE,BONN,NW,50.73,7.10,92.122.215.67
+IN,AHMADABAD,GJ,23.03,72.62,96.17.182.136
+US,NEWPORTNEWS,VA,37.0588,-76.4641,96.6.47.120
+US,TERREHAUTE,IN,39.4668,-87.4112,107.14.38.217
+US,PERRYTON,TX,36.2791,-100.8094,23.74.8.24
+US,GONZALES,LA,30.2383,-90.9202,23.215.15.22
+US,POTTSVILLE,PA,40.6882,-76.264,23.67.242.156
+US,PARKERSBURG,WV,39.2786,-81.5101,96.17.9.14
+US,FLINT,MI,43.0125,-83.6878,23.67.60.220
+US,LITHONIA,GA,33.6707,-84.1416,72.246.247.5
+NZ,PARADISE,"",-44.73,168.37,184.28.126.7
+US,ENTERPRISE,AL,31.4127,-85.8669,184.26.93.116
+US,SAINTPETERS,MO,38.8003,-90.6176,204.93.47.220
+US,PRINCETON,WV,37.3649,-81.0293,184.28.17.76
+OM,MASQAT,"",23.61,58.59,23.57.69.159
+JP,KOBE,28,34.68,135.17,117.104.139.136
+FR,LILLE,"",50.63,3.07,2.20.243.42
+US,PERRYVILLE,MO,37.7127,-89.8903,96.17.14.16
+US,ELKGROVE,CA,38.4313,-121.306,23.61.195.163
+US,ROSLYN,NY,40.8044,-73.641,184.26.44.42
+US,BROOMFIELD,CO,39.9510,-105.0448,63.235.21.140
+US,FONTANA,CA,34.0924,-117.4344,184.50.26.201
+US,LITTLETON,CO,39.5942,-105.0086,107.14.43.30
+GB,LEWISHAM,EN,51.45,-0.02,23.67.255.106
+US,SEMINOLE,FL,27.8440,-82.797,165.254.205.13
+PR,CAYEY,"",18.1193,-66.1642,72.164.253.83
+US,MAINEVILLE,OH,39.3164,-84.2265,165.254.207.111
+US,SINTON,TX,28.0577,-97.5365,96.17.163.161
+US,SEAFORD,DE,38.6412,-75.6063,23.192.161.21
+RU,ORENBURG,"",51.78,55.05,80.239.217.238
+US,PINEBLUFF,AR,34.1930,-91.9403,184.28.23.4
+US,BOYDTON,VA,36.6580,-78.3793,184.27.45.157
+US,WICHITA,KS,37.6923,-97.3374,23.215.15.9
+US,CEDARFALLS,IA,42.5035,-92.4936,23.63.227.225
+US,LITTLEFERRY,NJ,40.8469,-74.0394,24.143.199.156
+US,CALERA,AL,33.1091,-86.7183,23.79.240.48
+DE,SCHWALBACH,HE,50.15,8.53,2.22.61.99
+AW,ORANJESTAD,"",12.52,-70.03,23.74.2.12
+US,HAMPTON,SC,32.9081,-81.0847,184.27.45.150
+US,PITTSBURGH,PA,40.4747,-79.9521,184.26.44.40
+US,WARREN,NJ,40.6309,-74.5141,213.248.117.201
+MA,CASABLANCA,"",33.59,-7.62,92.123.73.26
+US,ALEXANDRIA,VA,38.8194,-77.0596,23.192.161.21
+NC,NOUMEA,"",-22.27,166.45,104.72.70.96
+US,STRUTHERS,OH,41.0502,-80.5914,107.14.38.217
+US,NAPERVILLE,IL,41.7638,-88.1463,107.14.38.224
+US,PASOROBLES,CA,35.6618,-120.7074,23.216.10.54
+US,BELTON,TX,31.0788,-97.4732,184.26.93.116
+DE,WUPPERTAL,NW,51.27,7.18,80.157.170.158
+US,DESOTO,TX,32.5973,-96.864,184.28.23.4
+US,FORTWAINWRIGHT,AK,64.8285,-147.6246,165.254.1.165
+MY,BAHARU,"",6.85,116.83,23.5.165.167
+AU,TOOWOOMBA,QLD,-27.55,151.97,23.62.157.31
+AU,MACKAY,QLD,-21.15,149.20,23.209.183.50
+US,RANCHOPALOSVERDES,CA,33.7553,-118.3641,184.50.26.203
+NZ,GLENFIELD,"",-36.77,174.73,219.88.186.172
+IN,INDORE,MP,22.72,75.83,23.211.135.110
+US,FEDERALWAY,WA,47.3073,-122.3138,23.212.59.90
+CN,XIAN,SN,34.26,108.94,72.246.191.16
+US,MACOMB,MI,42.6839,-82.9078,23.67.60.220
+US,WAPPINGERSFALLS,NY,41.5960,-73.8849,184.51.125.79
+JP,KANAZAWA,17,36.57,136.65,117.104.139.162
+US,MCDONOUGH,GA,33.4474,-84.1473,184.28.127.58
+US,WINDSORMILL,MD,39.3333,-76.7813,23.67.242.156
+US,REEDLEY,CA,36.6362,-119.4115,184.84.180.92
+US,NEWROADS,LA,30.7095,-91.4494,205.185.195.170
+US,LOWELL,MA,42.6562,-71.3029,184.25.109.196
+US,MCLEAN,VA,38.9398,-77.1677,184.27.45.157
+US,SPRINGVILLE,UT,40.1286,-111.4916,23.61.195.165
+US,CAPITOLHEIGHTS,MD,38.9876,-76.8808,23.192.161.21
+RU,PERM,"",58.00,56.25,80.239.217.238
+US,XENIA,OH,39.6596,-83.8999,65.113.249.8
+US,BOULDER,CO,40.0440,-105.194,184.84.180.98
+US,NORCO,CA,33.9289,-117.5482,184.87.195.99
+US,BUCKHANNON,WV,38.9980,-80.2065,184.27.45.150
+FR,ORLEANS,"",47.92,1.90,81.52.201.77
+US,DEQUEEN,AR,34.0794,-94.3022,63.216.54.231
+BN,BANDARSERIBEGAWAN,"",4.88,114.93,23.75.23.140
+DE,COTTBUS,BB,51.77,14.33,80.157.150.169
+NL,UTRECHT,"",52.08,5.13,95.101.2.112
+US,MAMARONECK,NY,40.9533,-73.7381,184.51.125.68
+MX,LOSMOCHIS,SIN,25.77,-108.97,173.223.52.70
+AU,CHATSWOOD,NSW,-33.80,151.18,23.62.8.25
+US,DUNCANVILLE,TX,32.6601,-96.9139,96.16.7.101
+US,FARMINGTON,ME,44.6583,-70.1012,107.14.38.218
+US,RAPIDCITY,SD,44.0755,-103.1782,107.14.38.227
+RU,SAMARA,"",53.20,50.15,80.239.237.80
+US,GIGHARBOR,WA,47.3779,-122.7277,23.212.59.63
+US,NACOGDOCHES,TX,31.6232,-94.6616,23.5.164.146
+US,LACROSSE,WI,43.8000,-91.145,184.85.215.170
+TR,MERSIN,"",36.80,34.63,95.100.169.112
+GB,NOTTINGHAM,EN,52.97,-1.17,88.221.87.94
+JP,NAGANO,20,36.65,138.18,23.3.104.16
+ID,BALI,"",-6.12,106.98,72.246.191.16
+US,WILDOMAR,CA,33.5994,-117.2537,184.50.26.194
+MY,SELANGOR,"",3.35,101.25,203.106.85.13
+US,RHINELANDER,WI,45.6521,-89.3386,184.85.215.170
+BW,GABORONE,"",-24.67,25.92,41.193.163.53
+MU,PORTLOUIS,"",-20.17,57.50,203.106.85.13
+US,DALYCITY,CA,37.6927,-122.4471,23.212.52.88
+JP,KYOTO,26,35.00,135.75,117.104.139.162
+US,MOODY,AL,33.6013,-86.5003,63.216.54.229
+US,CABOT,AR,34.9494,-92.0505,23.5.164.143
+DK,VALBY,"",55.65,12.52,23.65.29.93
+DE,TRAUNSTEIN,BY,47.88,12.65,195.145.147.108
+US,MOUNTLAUREL,NJ,39.9480,-74.9047,23.212.53.64
+US,BROOKLINE,MA,42.3337,-71.1298,184.29.107.20
+CZ,CESKA,"",49.28,16.57,23.74.24.69
+CA,NORTHYORK,ON,43.79,-79.43,72.246.43.232
+MX,MATAMOROS,TAM,25.88,-97.50,165.254.16.86
+TH,DINDAENG,"",12.80,102.08,203.144.145.96
+US,SPANISHFORT,AL,30.6968,-87.8613,96.17.153.157
+GB,SWINDON,EN,51.52,-1.78,96.17.163.165
+US,CHAPELHILL,NC,35.8944,-79.0318,209.18.41.23
+US,EASTPEORIA,IL,40.7043,-89.529,23.67.60.222
+US,SANJACINTO,CA,33.7837,-116.9578,23.216.10.54
+US,WOOSTER,OH,40.8061,-81.9813,107.14.38.227
+BR,JOINVILLE,SC,-26.30,-48.83,72.246.216.144
+US,SIOUXCITY,IA,42.4941,-96.3985,65.113.249.11
+CN,NANCHANG,JX,28.68,115.88,23.76.205.90
+KZ,KARAGANDA,"",49.80,73.10,2.22.52.101
+DE,RECKLINGHAUSEN,NW,51.62,7.20,23.14.94.224
+PF,PAPEETE,"",-17.53,-149.57,64.145.95.126
+FR,CAEN,"",49.18,-0.35,2.20.243.42
+GB,SIDCUP,EN,51.42,0.12,23.61.251.145
+US,PULLMAN,WA,46.7352,-117.1817,212.143.162.169
+US,FORNEY,TX,32.7342,-96.451,23.212.53.64
+US,MERIDIAN,ID,43.6053,-116.4124,192.80.13.117
+US,NIXA,MO,37.0415,-93.3061,23.5.164.143
+US,LAUREL,MD,39.0931,-76.8847,184.28.17.55
+MX,TEPIC,NAY,21.50,-104.90,173.223.52.70
+DE,SINSHEIM,BW,49.26,8.88,80.157.150.197
+LR,MONROVIA,"",6.31,-10.80,217.212.227.31
+US,BEREA,KY,37.5750,-84.2637,23.74.8.8
+US,CANALFULTON,OH,40.8849,-81.5861,205.185.195.183
+NG,LAGOS,"",6.45,3.40,2.20.44.118
+US,SOUTHPASADENA,CA,34.1101,-118.1575,184.50.26.201
+US,LITTLEELM,TX,33.1913,-96.9829,23.5.164.143
+US,LOVELAND,CO,40.3726,-105.133,184.84.180.92
+ZA,SILVERTON,"",-25.73,28.33,165.165.46.40
+US,SHAWNEE,OK,35.3679,-96.9107,174.76.226.117
+IT,TURIN,"",45.05,7.67,2.18.240.114
+US,BRADENTON,FL,27.4044,-82.4667,204.93.33.140
+RO,CLUJNAPOCA,"",46.77,23.60,80.15.235.163
+FR,TOULON,"",43.12,5.93,81.52.201.85
+US,WESTMINSTER,CA,33.7517,-117.9944,184.50.26.201
+US,MALDEN,MA,42.4305,-71.0574,184.25.109.196
+US,MISSOULA,MT,46.8557,-114.0158,107.14.32.228
+US,YAKIMA,WA,46.6267,-120.4248,184.27.179.187
+US,AVENEL,NJ,40.5832,-74.2709,23.67.60.220
+US,NORTHHOLLYWOOD,CA,34.1679,-118.3721,184.50.26.201
+DE,LEER,NI,53.23,7.43,80.157.150.197
+US,REVERE,MA,42.4188,-71.0044,184.25.109.200
+HK,CENTRALDISTRICT,"",22.28,114.15,23.76.205.90
+US,TROUTDALE,OR,45.5277,-122.3738,23.212.59.78
+RU,IVANOVO,"",55.81,36.11,2.21.240.40
+US,MISSION,TX,26.3187,-98.3913,23.215.15.22
+US,FORTBRAGG,CA,39.4588,-123.7157,23.61.195.163
+US,CIRCLEVILLE,OH,39.5752,-82.907,107.14.38.218
+US,BELLEROSE,NY,40.7366,-73.7227,23.67.242.139
+US,POMONA,CA,34.0419,-117.7548,184.50.26.194
+US,MATHER,CA,37.8825,-119.8558,96.17.12.48
+US,EVANS,GA,33.5549,-82.1635,184.27.45.157
+US,HARTFORD,CT,41.7826,-72.6613,184.25.109.200
+NZ,RICCARTON,"",-43.53,172.59,219.88.186.165
+SE,BLACKEBERG,AB,59.35,17.87,213.155.156.207
+UG,KAMPALA,"",0.32,32.58,41.193.163.53
+US,PALMDESERT,CA,33.7547,-116.336,107.14.44.212
+US,MONTEREY,CA,36.5816,-121.8436,96.17.12.48
+US,BECKLEY,WV,37.8169,-81.243,184.28.17.76
+US,SOUTHSANFRANCISCO,CA,37.6562,-122.4257,23.61.195.165
+US,GRANTSPASS,OR,42.6114,-123.7001,206.104.149.146
+US,HUNTSVILLE,AL,34.7252,-86.5616,23.79.240.36
+US,REDBUD,IL,38.1575,-89.9813,23.74.8.8
+CA,HALIFAX,NS,44.65,-63.60,184.29.107.38
+US,EMORY,TX,32.8293,-95.7283,23.212.53.64
+MX,PUEBLA,PUE,19.05,-98.20,23.212.53.75
+US,DEFOREST,WI,43.2338,-89.3318,184.85.215.165
+US,PASCO,WA,46.4588,-118.8176,184.27.179.159
+US,SUGARLAND,TX,29.6334,-95.63,23.212.53.64
+AR,DEMAYO,"",-25.92,-54.58,65.121.209.127
+US,FLORISSANT,MO,38.8119,-90.347,23.215.15.32
+US,FOXBORO,MA,42.0631,-71.2456,184.25.109.196
+CZ,HLUBOKANADVLTAVOU,"",49.05,14.43,23.62.237.138
+US,WILSONVILLE,OR,45.3090,-122.7696,184.27.179.181
+US,MAYNARD,MA,42.4225,-71.4615,184.25.109.196
+US,COLUMBIA,TN,35.6275,-86.9932,23.61.195.163
+US,SUNCITYCENTER,FL,27.7206,-82.4333,23.33.186.134
+US,LEMOORE,CA,36.2897,-119.848,23.212.52.79
+US,ENOLA,PA,40.2947,-76.9833,165.254.96.242
+US,SANTAANA,CA,33.7484,-117.8593,184.50.26.204
+DE,KARLSRUHE,BW,49.00,8.39,23.14.94.228
+AR,DORREGO,"",-38.70,-61.28,200.123.201.215
+DE,GERA,TH,50.87,12.08,194.25.95.219
+US,LEWISTON,ME,44.0905,-70.1653,107.14.38.217
+US,BROWNSVILLE,TX,26.0002,-97.5729,184.26.93.116
+US,LAKEWOOD,CA,33.8539,-118.1333,23.216.10.48
+CA,MARKHAM,ON,43.87,-79.27,72.246.43.215
+US,GREENWOOD,IN,39.6166,-86.1775,23.67.60.220
+RU,VOSTOCHNAYA,"",62.12,34.03,213.155.156.208
+US,WINTERGARDEN,FL,28.5650,-81.5866,23.33.186.134
+US,MELROSEPARK,IL,41.9027,-87.8623,184.27.45.150
+US,CLUTE,TX,29.0650,-95.3887,23.212.53.64
+US,ABSECON,NJ,39.4748,-74.4723,23.61.195.165
+US,ALABASTER,AL,33.2261,-86.7662,72.246.247.30
+US,ELIZABETH,NJ,40.6709,-74.179,184.51.125.79
+MK,SKOPJE,"",42.00,21.43,23.76.205.111
+US,TUSTIN,CA,33.7360,-117.8185,107.14.44.185
+US,ORANGEBURG,SC,33.4964,-80.8317,209.18.41.23
+US,BRYAN,TX,30.6361,-96.3666,204.2.223.90
+US,CHINO,CA,34.0123,-117.6883,184.50.26.201
+US,PIMA,AZ,32.9846,-109.9963,23.212.52.79
+RS,TOPOLA,"",43.88,21.19,184.27.179.159
+US,DAYTON,OH,39.7587,-84.1919,107.14.38.217
+RU,BRYANSK,"",53.24,34.35,2.21.240.40
+US,REGOPARK,NY,40.7254,-73.8614,24.143.199.188
+SG,AYERRAJAH,"",1.30,103.78,203.26.28.181
+AE,FUJAIRAH,"",25.12,56.34,2.20.249.12
+US,WINTERHAVEN,FL,27.9768,-81.764,23.33.186.101
+US,CERES,CA,37.5547,-120.9558,23.216.10.54
+US,GLENVIEW,IL,42.0783,-87.8242,23.67.60.220
+US,BEAUMONT,CA,33.9205,-116.9736,23.216.10.78
+US,SANJUANCAPISTRANO,CA,33.5241,-117.605,23.5.164.143
+US,SHAWNEEMISSION,KS,39.0276,-94.6559,23.77.234.11
+US,BISMARCK,ND,46.8193,-100.7748,107.14.38.218
+PH,DAVAO,"",7.07,125.60,202.78.83.170
+MX,SANPEDROCHOLULA,PUE,19.68,-97.97,201.148.68.240
+FR,CAPELLE,"",49.05,0.48,77.67.27.250
+IR,HAMADAN,"",34.80,48.52,23.62.238.220
+US,NEWHAVEN,CT,41.3083,-72.9287,184.28.17.76
+US,BROCKTON,MA,42.0777,-71.0422,184.25.109.208
+US,TULLAHOMA,TN,35.3402,-86.229,184.51.35.226
+MX,CIUDADOBREGON,SON,27.48,-109.93,187.141.186.95
+UA,KRASNOPEREKOPSK,CRIMEA,45.95,33.79,2.21.240.40
+RU,NAUKA,"",51.97,49.77,80.239.149.123
+UA,DONETSK,"",48.00,37.80,213.155.156.206
+US,NORASPRINGS,IA,43.1638,-92.9674,23.212.53.75
+US,CHALFONT,PA,40.2892,-75.2124,72.247.10.237
+DE,DRESDEN,SN,51.05,13.75,80.157.150.201
+US,TULSA,OK,36.1537,-95.9926,23.212.53.75
+US,ROHNERTPARK,CA,38.3267,-122.7061,23.212.52.79
+US,MOUNTPLEASANT,SC,32.8517,-79.8228,184.27.45.157
+US,WILLIAMSPORT,PA,41.1994,-77.0775,23.192.161.21
+US,FOOTHILLRANCH,CA,33.6255,-117.6932,184.50.26.204
+FR,REIMS,"",49.25,4.03,81.52.201.77
+US,GALION,OH,40.7120,-82.796,23.74.8.24
+BR,FORTALEZA,CE,-3.72,-38.50,190.98.140.184
+US,FERRIS,TX,32.5206,-96.6077,184.25.157.169
+US,CHELSEA,AL,33.3864,-86.611,23.220.100.223
+US,OSSINING,NY,41.1949,-73.8307,184.26.44.38
+BR,MARINGA,PR,-23.42,-51.92,72.246.216.139
+US,ANNANDALE,VA,38.8275,-77.2418,96.6.47.106
+US,PORTER,TX,30.1192,-95.2824,23.212.53.64
+US,PATCHOGUE,NY,40.7718,-72.9949,184.26.44.42
+DE,BIELEFELD,NW,52.03,8.53,80.157.150.197
+US,COLORADOSPRINGS,CO,38.8336,-104.8206,63.151.29.15
+DE,MUNSTER,NW,51.97,7.63,80.157.170.221
+JP,NAHA,47,26.21,127.68,72.246.184.92
+US,TUALATIN,OR,45.3689,-122.7641,184.84.180.92
+US,CLARKSDALE,MS,34.1809,-90.6118,23.212.53.75
+ES,BILBAO,"",43.25,-2.97,77.67.41.223
+US,HALTOMCITY,TX,32.8036,-97.2675,204.93.47.220
+DE,TRIER,RP,49.75,6.63,194.25.95.212
+GB,LEEDS,EN,53.80,-1.58,23.67.255.158
+US,GAMBIER,OH,40.3386,-82.3417,184.27.45.157
+US,CAMBRIDGE,MA,42.3802,-71.1347,184.25.109.200
+US,RIVERTON,UT,40.4909,-112.0097,23.61.195.165
+US,WAYNE,NJ,40.9484,-74.2449,184.26.44.38
+US,CARROLLTON,GA,33.5541,-85.0099,23.79.240.36
+US,PEARLAND,TX,29.5651,-95.2786,23.212.53.64
+US,BELL,CA,33.9704,-118.1852,184.50.26.179
+US,SOUTHLAKE,TX,32.9492,-97.1451,23.215.15.9
+US,DESTREHAN,LA,29.9844,-90.363,174.76.226.110
+US,DESPLAINES,IL,42.0490,-87.8913,107.14.38.218
+DE,DESSAU,ST,51.83,12.25,80.157.170.158
+ZA,PRETORIA,"",-25.71,28.23,165.165.46.40
+US,COLLEGESTATION,TX,30.5416,-96.2298,107.14.43.29
+US,SANDUSKY,MI,43.4191,-82.8598,23.212.53.64
+AU,WAVERLEY,NSW,-33.90,151.27,23.62.8.25
+FR,CLERMONTFERRAND,"",45.78,3.08,2.20.243.45
+US,SOUTHGATE,CA,33.9490,-118.202,184.50.26.203
+ME,PODGORICA,"",42.44,19.26,23.14.94.228
+US,CHATSWORTH,CA,34.2895,-118.607,184.87.195.99
+US,LAKESIDE,CA,32.9105,-116.888,23.216.10.54
+US,LAKEELSINORE,CA,33.5976,-117.3895,184.50.26.179
+US,ROCKFORD,IL,42.3405,-89.1484,23.67.60.222
+EE,TALLINN,"",59.43,24.73,213.155.156.207
+US,ORONO,ME,45.0868,-68.6498,23.74.8.8
+MN,ULAANBAATAR,"",47.92,106.92,23.76.205.90
+US,KETCHIKAN,AK,55.5909,-131.3492,184.27.179.181
+US,LOGAN,UT,41.6898,-111.6435,173.197.192.214
+AT,LINZ,"",48.30,14.30,2.16.217.211
+US,ROUNDROCK,TX,30.5230,-97.6428,107.14.43.30
+US,YUKON,OK,35.5068,-97.7625,23.215.15.9
+RU,POTOK,"",59.46,35.15,23.14.94.224
+VN,DUNG,"",19.83,105.25,23.75.23.135
+JP,KOSE,37,34.47,134.15,23.15.1.55
+BY,GOMEL,"",55.32,28.78,92.122.189.85
+IR,TABRIZ,"",38.08,46.29,23.74.24.69
+RU,TAGIL,"",56.00,51.50,2.21.240.40
+CN,HOHHOT,NM,40.81,111.65,72.246.191.16
+CO,BARRANQUILLA,"",10.98,-74.80,200.14.44.103
+US,MYRTLEBEACH,SC,33.7665,-78.7956,184.27.45.150
+US,SEDALIA,MO,38.6763,-93.2612,65.113.249.8
+US,BOONVILLE,MO,38.8814,-92.7602,96.16.7.101
+CA,OSHAWA,ON,43.90,-78.87,72.246.43.215
+US,PITTSBURG,CA,38.0121,-121.92,23.212.52.79
+US,PORTHURON,MI,42.9793,-82.4643,65.113.249.8
+DE,KALTENBACH,RP,49.20,7.75,80.157.150.197
+US,ELLENDALE,ND,46.0577,-98.4986,107.14.38.224
+US,CARLISLE,PA,40.1805,-77.2345,65.113.249.11
+PR,HUMACAO,"",18.1494,-65.8294,72.246.65.37
+US,MERCED,CA,37.2829,-120.4535,23.212.52.79
+US,TEMPLEHILLS,MD,38.8182,-76.9414,23.192.161.21
+US,LAJOLLA,CA,32.8548,-117.2497,23.216.10.54
+US,BROOKVILLE,OH,39.8424,-84.4242,107.14.38.217
+US,SEVIERVILLE,TN,35.7905,-83.4826,23.79.240.36
+US,SNOHOMISH,WA,47.9468,-122.0122,23.74.8.24
+US,WHITEVILLE,NC,34.2997,-78.6775,184.27.45.157
+US,ELDORADO,AR,33.1732,-92.6868,23.5.164.146
+US,UNIVERSITYPARK,PA,40.8092,-77.8868,96.6.47.120
+US,SUFFOLK,VA,36.8725,-76.5524,96.6.47.120
+CA,LETHBRIDGE,AB,49.70,-112.83,24.244.17.205
+BR,BELEM,PA,-1.45,-48.48,177.159.174.13
+CN,KUNMING,YN,25.04,102.72,72.246.191.19
+BY,MINSK,"",53.90,27.57,2.20.142.173
+AU,LOXTON,SA,-34.45,140.57,60.254.143.219
+US,CORAM,NY,40.8776,-73.0024,184.26.44.42
+DE,LUBECK,SH,53.87,10.70,194.25.95.214
+US,GREATLAKES,IL,42.3045,-87.8638,23.67.60.223
+US,CARTHAGE,NY,43.9769,-75.558,107.14.38.227
+NZ,DUNEDIN,"",-45.87,170.50,219.88.186.164
+US,DICKSON,TN,36.0826,-87.4349,23.79.240.36
+US,RUIDOSO,NM,33.3909,-105.6341,173.223.52.67
+BR,BELOHORIZONTE,MG,-19.92,-43.93,200.174.107.50
+DE,ROSTOCK,MV,54.08,12.13,194.25.95.214
+US,WILKESBORO,NC,36.1256,-81.1459,204.93.62.75
+DE,WEIDEN,RP,49.82,7.30,2.16.217.206
+US,IRONMOUNTAIN,MI,45.9025,-88.0366,165.254.207.117
+US,LYNWOOD,CA,33.9236,-118.2003,184.87.195.99
+RU,YAROSLAVL,"",57.62,39.87,2.21.240.40
+US,PACOIMA,CA,34.2561,-118.4203,184.50.26.179
+US,BARTLETT,IL,41.9753,-88.1848,23.67.60.217
+CA,SIMCOE,ON,42.83,-80.30,72.246.43.232
+US,SUMMERVILLE,SC,33.0633,-80.1896,209.18.41.27
+US,JEFFERSONCITY,MO,38.5003,-92.1516,209.170.117.178
+US,LAFAYETTE,LA,30.2373,-91.9924,23.215.15.22
+US,CHESAPEAKE,VA,36.7522,-76.2168,23.212.53.64
+CH,DIETIKON,"",47.42,8.40,193.45.15.198
+RU,VLADIVOSTOK,"",43.13,131.90,96.7.251.95
+US,EXTON,PA,40.0430,-75.64,23.67.242.139
+US,CAROLSTREAM,IL,41.9125,-88.1349,107.14.38.217
+MY,KUALAKANGSAR,"",4.77,100.93,58.26.185.142
+US,TUCKER,GA,33.8539,-84.2185,72.246.247.30
+CN,GUOJI,JS,34.06,117.41,23.15.10.106
+US,MIAMISBURG,OH,39.6178,-84.2528,107.14.38.217
+US,DEKALB,IL,41.8888,-88.7558,23.67.60.223
+FR,NIMES,"",43.83,4.35,2.16.117.190
+BR,SALVADOR,BA,-12.98,-38.52,200.174.107.42
+US,NORTON,MA,41.9632,-71.1829,23.62.238.215
+US,BOTHELL,WA,47.7527,-122.2153,184.84.180.101
+US,TROY,OH,40.0416,-84.1531,23.74.8.8
+US,STAFFORD,VA,38.4716,-77.4391,184.26.44.40
+US,ORRVILLE,OH,40.8369,-81.7632,2.22.52.101
+US,LEBANON,MO,37.6765,-92.6098,63.216.54.216
+US,WACO,TX,31.5520,-97.1385,23.212.53.64
+FR,CHOISYLEROI,"",48.77,2.42,2.16.117.190
+US,HARTSVILLE,SC,34.3720,-80.0853,209.18.41.27
+US,FAIRVIEW,OR,45.5383,-122.4348,23.212.59.90
+US,GLENDORA,CA,34.1187,-117.8538,184.50.26.204
+US,CRANSTON,RI,41.7750,-71.4355,23.67.244.226
+US,MUNDELEIN,IL,42.2666,-88.0352,107.14.38.217
+US,NILES,IL,42.0285,-87.8124,23.67.60.222
+US,SEBASTIAN,FL,27.7861,-80.4788,23.79.240.48
+RU,YAKUTSK,"",62.00,129.67,2.21.240.40
+RU,ULYANOVSK,"",52.12,34.41,217.212.227.25
+AU,BALAKLAVA,SA,-34.15,138.42,210.11.142.65
+DE,BAUTZEN,SN,51.18,14.43,80.157.150.201
+US,WORCESTER,MA,42.2627,-71.8028,63.141.200.248
+CH,VERNIER,"",46.22,6.08,193.247.167.214
+TR,DENIZLI,"",40.90,29.53,193.45.15.199
+US,HOUMA,LA,29.5867,-90.8252,23.212.53.75
+US,EASTWENATCHEE,WA,47.4725,-120.2224,184.27.179.179
+US,NORTHPOLE,AK,64.7816,-147.3481,23.212.59.64
+US,GALLATIN,TN,36.4052,-86.4555,23.79.240.36
+CA,AYLMER,ON,42.78,-80.98,72.246.43.237
+US,ODESSA,TX,31.8458,-102.3673,23.212.53.75
+US,CHALMETTE,LA,29.9614,-89.9537,23.215.15.18
+US,SOUTHYARMOUTH,MA,41.6739,-70.1961,184.25.109.196
+US,SIGNALHILL,CA,33.7834,-118.1506,184.50.26.179
+US,HARRISONBURG,VA,38.5056,-78.9398,184.28.17.76
+US,FRANKLIN,VA,36.6905,-76.9426,184.28.17.76
+US,MISSOURICITY,TX,29.5470,-95.5308,23.212.53.75
+US,CLERMONT,FL,28.4862,-81.7428,72.164.253.83
+US,CHERAW,SC,34.6398,-79.9151,209.18.41.23
+US,SOUTHHILL,VA,36.7430,-78.1806,184.29.107.38
+US,LAGUNAHILLS,CA,33.5987,-117.7127,184.50.26.203
+SG,BEDOK,"",1.33,103.94,23.75.23.135
+US,LANGDON,ND,48.8344,-98.3538,63.216.54.231
+US,BALLWIN,MO,38.6038,-90.5556,204.93.47.216
+US,TULIA,TX,34.5509,-101.7483,23.74.8.24
+JP,MATSUSAKA,24,34.57,136.53,23.15.1.29
+RU,UFA,"",54.73,55.93,217.212.227.25
+US,SANRAFAEL,CA,37.9769,-122.5052,23.212.52.79
+SK,BRATISLAVA,"",48.15,17.12,23.14.94.220
+US,LOCKPORT,NY,43.1860,-78.742,184.29.107.20
+KZ,SHYMKENT,"",42.30,69.60,80.239.222.190
+MD,CHISINAU,"",47.01,28.86,92.122.189.114
+US,PLATTSBURGH,NY,44.7370,-73.4626,63.141.200.248
+GB,HARINGEY,EN,51.58,-0.08,23.67.255.158
+US,OSKALOOSA,IA,41.3158,-92.6258,65.113.249.8
+CA,GUELPH,ON,43.55,-80.25,67.231.211.237
+US,HILLSBORO,OR,45.4461,-122.9838,63.217.232.22
+US,PLAINFIELD,NJ,40.6310,-74.4312,184.26.44.42
+IN,DEHRADUN,UL,30.32,78.03,96.17.182.130
+ES,ZARAGOZA,"",41.63,-0.88,80.149.168.109
+US,SANBERNARDINO,CA,34.1053,-117.2917,23.216.10.78
+US,LITCHFIELD,CT,41.7562,-73.2062,184.51.125.68
+DE,MEPPEN,NI,52.68,7.32,80.157.170.231
+FR,BOISDARCY,"",48.80,2.02,2.16.117.190
+SI,LJUBLJANA,"",46.06,14.51,23.62.237.138
+US,CONVERSE,TX,29.5102,-98.277,184.26.93.116
+US,RARITAN,NJ,40.5726,-74.6423,184.26.44.38
+US,DEVINE,TX,29.1707,-98.9599,96.17.163.161
+reserved,reserved,reserved,reserved,reserved,63.80.12.225
+DE,DEGGINGEN,BW,48.60,9.72,23.14.94.224
+US,PIEDMONT,SC,34.7207,-82.4772,23.79.240.48
+US,MANHATTANBEACH,CA,33.8907,-118.3967,23.216.10.54
+IR,TEHRAN,"",35.67,51.42,184.29.107.20
+US,ITHACA,NY,42.4320,-76.4974,69.31.77.208
+US,NORWALK,CA,33.9069,-118.082,23.216.10.54
+US,WILLOUGHBY,OH,41.6111,-81.3789,107.14.38.224
+US,RUSSELLVILLE,AR,35.2872,-93.0945,23.5.164.143
+US,WATSONVILLE,CA,36.9274,-121.7472,63.233.61.151
+US,LORENA,TX,31.3976,-97.22,107.14.43.29
+GB,OLDHAM,EN,53.55,-2.12,88.221.87.94
+US,SPRINGDALE,AR,36.1895,-94.2305,23.215.15.9
+US,WASCO,CA,35.6321,-119.4058,184.87.195.109
+US,NORTHEAST,MD,39.5890,-75.9588,23.192.161.16
+CN,CHONGQING,CQ,29.56,106.55,23.76.205.90
+BD,MEDIA,"",23.13,89.18,23.57.76.20
+NZ,NAPIER,"",-39.48,176.92,219.88.186.164
+US,HENDERSON,NV,36.0394,-114.9813,165.254.144.32
+US,PEORIA,AZ,33.5921,-112.4065,184.50.26.179
+US,THOMASVILLE,NC,35.8640,-80.1016,209.18.41.23
+US,HOPEMILLS,NC,34.9210,-78.9114,209.18.41.27
+KG,BISHKEK,"",42.90,74.60,80.239.217.238
+US,UPPERDARBY,PA,39.9602,-75.2702,184.29.107.20
+JP,TOKUSHIMA,36,34.07,134.57,72.246.184.84
+US,CLARKSVILLE,TN,36.5878,-87.3074,165.254.138.175
+US,RIDGECREST,CA,35.7401,-117.4536,184.50.26.179
+RO,ROSIORIIDEVEDE,"",44.12,24.98,81.196.26.237
+US,RENO,NV,39.5263,-119.8124,23.216.10.78
+US,KENOSHA,WI,42.6168,-87.8302,65.113.249.11
+BY,BREST,"",52.10,23.70,217.212.227.31
+US,GREENFIELD,IN,39.7974,-85.7653,65.113.249.11
+IE,CASHEL,"",52.52,-7.89,88.221.222.34
+US,STARKVILLE,MS,33.4256,-88.8438,208.185.55.117
+LT,KAUNAS,"",54.90,23.90,2.21.240.61
+DE,WESEL,NW,51.67,6.62,80.157.170.154
+US,WESTERNSPRINGS,IL,41.8114,-87.9019,23.67.60.223
+DE,WURZBURG,BY,49.79,9.94,195.145.147.109
+US,SANRAMON,CA,37.7661,-121.9734,23.61.195.165
+DE,MAGDEBURG,ST,52.17,11.67,80.157.150.201
+US,CROWNPOINT,IN,41.4039,-87.3294,23.67.60.223
+US,PALMHARBOR,FL,28.0778,-82.7637,192.204.11.246
+SE,SODERTALJE,AB,59.20,17.62,2.21.240.61
+US,LAMONI,IA,40.6492,-93.957,23.67.60.223
+US,KEYLARGO,FL,25.2553,-80.3918,23.79.240.36
+PL,ZAMOSC,"",52.13,21.12,2.22.52.109
+US,MOORPARK,CA,34.2858,-118.8813,63.235.21.147
+US,GARDNERVILLE,NV,38.7983,-119.574,184.85.249.14
+US,EVERETT,WA,47.9874,-122.2011,23.212.59.63
+US,SYLMAR,CA,34.3277,-118.3895,184.50.26.201
+US,LAWRENCEVILLE,GA,33.9563,-83.9881,23.79.240.36
+CA,PRINCERUPERT,BC,54.32,-130.33,184.27.179.181
+US,GLADSTONE,OR,45.3872,-122.5921,23.212.59.63
+US,HARWOODHEIGHTS,IL,41.9530,-87.7822,23.67.60.223
+US,SAINTCHARLES,IL,41.9372,-88.2876,107.14.38.224
+US,COVINA,CA,34.0976,-117.9068,23.216.10.54
+VN,PHUONG,"",17.17,106.92,23.2.16.104
+US,VERNONHILLS,IL,42.2230,-87.9651,23.67.60.223
+RU,TAMBOV,"",52.73,41.43,80.239.237.231
+MM,YANGON,"",16.78,96.17,203.106.85.13
+CH,PULLY,"",46.52,6.65,193.247.167.211
+US,HICKORY,NC,35.7628,-81.3219,23.79.240.37
+US,HOLLYSPRINGS,NC,35.6211,-78.8587,63.151.29.15
+GB,NEWBURY,EN,51.40,-1.32,23.212.108.8
+US,SOUTHSALEM,NY,41.2554,-73.5385,184.26.44.42
+US,FORTWAYNE,IN,41.1306,-85.1289,23.67.60.223
+US,TAYLOR,MI,42.2256,-83.2685,23.67.60.222
+IN,GUNTUR,AP,16.30,80.45,23.57.69.161
+US,CUMBERLAND,MD,39.6528,-78.7626,184.28.17.55
+US,LANHAM,MD,38.9666,-76.8622,184.27.45.157
+RU,SAKHALIN,"",52.43,32.90,2.22.52.102
+US,NORFOLK,VA,36.8511,-76.2784,184.28.127.58
+US,YOUNGSTOWN,OH,41.0994,-80.6494,96.17.9.8
+CA,VERNON,BC,50.27,-119.27,24.244.17.205
+US,CASPER,WY,43.1744,-106.3605,107.14.32.228
+US,ELLICOTTCITY,MD,39.2673,-76.7986,23.67.242.139
+TW,TAICHUNG,"",24.15,120.68,61.220.62.175
+US,HACKENSACK,NJ,40.8892,-74.0466,23.67.242.139
+US,BONNEYLAKE,WA,47.1879,-122.183,23.212.59.85
+US,YORK,PA,39.9626,-76.7282,23.192.161.16
+DE,HAGEN,NW,51.03,7.43,195.95.193.147
+FR,POITIERS,"",46.58,0.33,2.20.243.45
+BR,COTIA,SP,-23.62,-46.93,72.246.216.139
+US,MILFORD,MA,42.1566,-71.5186,184.25.109.200
+DE,NEUBRANDENBURG,MV,53.57,13.27,195.95.193.132
+US,WILLIAMSBURG,KY,36.7356,-84.1501,23.220.148.122
+US,BENTONVILLE,AR,36.3232,-94.2666,23.77.234.11
+FR,TOULOUSE,"",43.60,1.43,2.20.243.45
+CA,YELLOWKNIFE,NT,62.45,-114.35,184.150.187.229
+US,COUDERSPORT,PA,41.7605,-77.9728,209.18.41.23
+DE,BRAUNSCHWEIG,NI,52.27,10.53,194.25.95.214
+AU,MIRANDA,NSW,-34.03,151.10,23.62.8.25
+US,SYLVANIA,OH,41.6992,-83.7379,23.74.8.24
+US,WESTCHESTER,PA,39.9842,-75.6084,184.27.45.157
+US,TULARE,CA,36.1798,-119.3666,23.212.52.79
+US,ELMHURST,NY,40.7372,-73.8787,184.29.107.38
+GR,IOANNINA,"",39.67,20.83,23.14.94.214
+JP,ASAHI,14,35.53,139.70,72.246.191.16
+US,LANSING,MI,42.7327,-84.5558,65.113.249.8
+US,TRABUCOCANYON,CA,33.6636,-117.5894,184.50.26.194
+US,CLEARWATER,FL,27.9797,-82.7794,72.164.253.83
+US,MORGANTON,NC,35.7567,-81.7518,23.79.240.48
+US,SIERRAMADRE,CA,34.1687,-118.0505,184.50.26.204
+US,SPRINGHILL,FL,28.4679,-82.5981,23.33.186.134
+US,TYLER,TX,32.3248,-95.3025,165.254.207.117
+US,IOWACITY,IA,41.6899,-91.4517,65.113.249.8
+US,MUSKOGEE,OK,35.6818,-95.3578,23.5.164.143
+US,LAKECHARLES,LA,30.2894,-93.0808,96.17.153.162
+US,LAKESTEVENS,WA,48.0434,-122.062,23.212.59.90
+JO,AL,"",31.82,35.83,80.239.154.193
+US,CARIBOU,ME,46.8928,-68.1493,107.14.38.218
+BG,PAZARDJIK,"",42.20,24.33,23.62.237.137
+JP,MATSUYAMA,38,33.84,132.76,184.51.199.132
+US,UNIVERSALCITY,TX,29.5519,-98.3081,107.14.43.30
+US,SIERRAVISTA,AZ,31.5436,-110.254,184.50.26.194
+US,VIRGINIABEACH,VA,36.8598,-75.9812,23.220.148.122
+AU,DANDENONG,VIC,-37.98,145.20,23.62.8.25
+CA,MISSISSAUGA,ON,43.15,-79.50,67.231.211.247
+CA,BRAMPTON,ON,43.68,-79.77,72.246.43.233
+UZ,ANDIJAN,"",40.78,72.34,2.22.52.105
+US,WHARTFORD,CT,41.7542,-72.7573,184.25.109.213
+JP,TAKAMATSU,37,34.33,134.05,117.104.139.136
+SO,MOGADISCIO,"",2.07,45.37,80.239.237.230
+US,SARASOTA,FL,27.3364,-82.5308,192.204.11.235
+AT,PURGSTALL,"",48.75,15.72,195.145.147.108
+RU,TOLYATTI,"",53.52,49.41,80.239.217.238
+US,MARQUETTE,MI,46.5095,-87.3836,184.85.215.170
+IN,KOCHI,KL,9.97,76.23,117.239.240.76
+US,EASTMAN,GA,32.2112,-83.1979,72.246.247.30
+US,ALBEMARLE,NC,35.3503,-80.2174,63.216.54.229
+US,CONCORD,NC,35.3735,-80.5212,209.18.41.27
+US,MOUNTPROSPECT,IL,42.0663,-87.9341,23.67.60.223
+DE,JENA,TH,50.93,11.58,23.14.94.220
+US,PERRY,GA,32.4431,-83.7439,23.215.15.22
+ES,ZAMUDIO,"",43.28,-2.87,92.123.73.221
+FR,DIJON,"",47.32,5.02,2.20.243.42
+US,MORENOVALLEY,CA,33.8879,-117.225,184.50.26.179
+US,YUCAIPA,CA,34.0360,-117.0172,184.50.26.179
+AU,BELROSE,NSW,-33.73,151.22,23.62.8.21
+US,DRIPPINGSPRINGS,TX,30.2468,-98.1159,65.116.149.102
+US,ONTARIO,CA,34.0635,-117.6503,184.50.26.179
+US,RIGBY,ID,43.6749,-111.8908,67.131.104.6
+US,ROCKVILLE,MD,39.0839,-77.1534,96.6.47.120
+US,CUYAHOGAFALLS,OH,41.1403,-81.4761,96.17.9.8
+US,WESTLAND,MI,42.3351,-83.3852,65.113.249.11
+CA,MILLBROOK,ON,44.15,-78.45,72.246.43.237
+GB,HAYES,EN,51.37,0.02,88.221.87.94
+CZ,HAVLICKUVBROD,"",49.62,15.58,23.62.237.135
+SI,MARIBOR,"",46.55,15.65,213.248.108.233
+JP,IBARAKI,27,34.82,135.57,202.229.2.213
+DE,OSNABRUCK,NI,52.27,8.05,80.157.170.231
+RU,MURMANSK,"",68.48,33.35,2.21.240.61
+US,WYLIE,TX,33.0138,-96.5409,23.215.15.32
+US,DADECITY,FL,28.3653,-82.1963,23.33.186.101
+US,DOYLESTOWN,PA,40.3369,-75.1195,65.113.249.11
+GB,BRENTFORD,EN,51.50,-0.32,23.67.255.158
+US,ROCKWALL,TX,32.8846,-96.42,96.16.7.120
+US,WAVERLY,OH,39.1500,-83.0509,107.14.38.227
+US,ABERDEEN,WA,47.1445,-123.7718,184.84.180.101
+US,TOLEDO,OH,41.6525,-83.5486,23.74.8.24
+US,SANPABLO,CA,37.9790,-122.3365,23.212.52.79
+US,LAGUNANIGUEL,CA,33.5425,-117.7825,184.50.26.194
+US,DEPEW,NY,42.9001,-78.7029,184.26.44.38
+US,LOSALTOS,CA,37.3688,-122.1527,23.212.52.88
+US,WATERFORD,CT,41.3583,-72.1558,165.254.48.150
+US,ASHEVILLE,NC,35.5948,-82.5572,23.79.240.37
+US,DENTON,TX,33.2208,-97.1437,204.93.47.216
+US,EPHRATA,PA,40.1811,-76.176,63.216.54.236
+US,DICKINSON,ND,46.9271,-102.7543,205.185.195.183
+US,PANAMACITY,FL,30.1608,-85.6475,23.212.53.75
+ID,MEDAN,"",3.58,98.67,23.0.162.46
+US,SUNLAND,CA,34.2589,-118.3307,107.14.44.212
+US,SANTAMARIA,CA,34.9332,-120.2665,23.212.52.79
+US,LEMONGROVE,CA,32.7331,-117.0343,184.50.26.179
+US,BRIDGETON,NJ,39.4433,-75.2554,184.26.44.38
+US,FLORENCE,OR,44.1259,-124.0315,165.254.96.248
+FR,BORDEAUX,"",44.83,-0.57,81.52.201.77
+VN,CANTHO,"",10.03,105.78,96.17.180.177
+MO,MACAU,"",22.20,113.55,202.175.5.87
+US,QUEENCREEK,AZ,33.3064,-111.8406,63.226.34.173
+AO,LUANDA,"",-8.82,13.23,23.62.100.154
+DE,SACK,BY,49.50,11.02,23.14.94.224
+EC,CUENCA,"",-2.88,-78.98,165.254.205.7
+US,LAKEWORTH,FL,26.6214,-80.0578,23.79.240.37
+US,MATTHEWS,NC,35.0912,-80.6904,63.216.54.236
+JP,SAPPORO,01,43.05,141.35,72.246.184.89
+US,CHANTILLY,VA,38.8959,-77.4456,184.85.249.6
+US,WESTMONT,IL,41.7959,-87.9751,107.14.38.218
+US,MORGANCITY,LA,29.8739,-91.2977,23.215.15.9
+US,OAKBROOK,IL,41.7836,-87.9391,23.67.60.222
+US,GREENSBORO,NC,36.0706,-79.7656,72.246.247.30
+US,CORTLAND,NY,42.5863,-76.1831,72.247.10.237
+AT,WIENERNEUDORF,"",48.07,16.32,195.145.147.108
+CZ,PRAHA,"",50.08,14.47,23.62.237.133
+NA,WINDHOEK,"",-22.57,17.08,41.193.163.53
+SZ,MBABANE,"",-26.32,31.13,41.193.163.45
+US,MANNING,SC,33.6434,-80.1966,184.51.35.215
+US,LOVETTSVILLE,VA,39.2666,-77.6386,2.20.142.166
+US,ISLIP,NY,40.7426,-73.2171,184.26.44.38
+US,MESQUITE,TX,32.7700,-96.614,107.14.43.30
+US,FERGUSFALLS,MN,46.2829,-96.0991,165.254.207.117
+AR,RIVADAVIA,"",-34.85,-58.37,184.50.26.179
+US,LASCRUCES,NM,32.6621,-106.6414,23.212.52.79
+US,GLASSBORO,NJ,39.6996,-75.1187,23.67.242.156
+KR,KISA,"",36.72,126.80,92.122.215.89
+US,PETALUMA,CA,38.2181,-122.773,23.212.52.88
+RU,KOLOMNA,"",55.08,38.78,213.155.156.212
+US,YUCCAVALLEY,CA,34.2832,-116.5958,184.50.26.203
+CL,VINADELMAR,"",-33.01,-71.52,190.98.143.69
+CA,THUNDERBAY,ON,48.40,-89.23,72.246.43.215
+US,CORPUSCHRISTI,TX,27.7980,-97.4011,23.212.53.75
+IN,VASHI,MH,18.75,73.03,23.57.69.157
+VN,DONGDA,"",22.63,106.40,23.5.165.167
+US,SEVERNAPARK,MD,39.0808,-76.5571,23.67.242.156
+US,ASHLAND,OR,42.1843,-122.5624,23.212.59.90
+ID,MALANG,"",-7.98,112.62,23.0.162.21
+GB,ASHFORD,EN,51.42,-0.47,23.67.255.158
+RU,SVERDLOVSK,"",56.85,60.60,2.21.240.40
+US,WESTERVILLE,OH,40.1219,-82.9191,96.17.9.14
+US,SULPHURSPRINGS,TX,33.1779,-95.567,23.5.164.146
+US,RATHDRUM,ID,47.8426,-116.9074,107.14.43.30
+US,EATON,CO,40.5202,-104.6808,23.215.15.9
+US,RIVERFALLS,WI,44.8561,-92.6272,23.67.60.222
+US,ANTELOPE,CA,38.7156,-121.3637,23.212.52.93
+SE,SKARHOLMEN,AB,59.28,17.88,217.212.227.25
+US,HEARNE,TX,30.8324,-96.5749,23.212.53.75
+US,WAUSAU,WI,45.0598,-89.4871,23.74.8.24
+US,ELGIN,IL,42.0350,-88.2392,23.67.60.222
+UZ,TASHKENT,"",40.13,68.37,2.21.240.61
+NP,KATHMANDU,"",27.72,85.32,23.212.108.8
+US,LAWRENCE,KS,39.0131,-95.2254,23.63.227.214
+US,ALPHARETTA,GA,34.1327,-84.2992,72.246.247.30
+US,ODENTON,MD,39.0496,-76.7176,23.192.161.21
+EC,QUITO,"",-0.22,-78.50,165.254.205.13
+TW,TAINAN,"",23.31,120.31,61.220.62.175
+CN,NINGBO,ZJ,29.88,121.54,23.15.10.106
+US,MANAHAWKIN,NJ,39.7102,-74.2577,184.26.44.42
+RU,ROSTOVNADONU,"",47.24,39.71,23.14.94.228
+US,"","",38.7657,-77.4852,184.25.157.169
+RU,CHELYABINSK,"",55.17,61.40,213.155.156.206
+US,WALLACE,NC,34.7667,-77.8738,63.151.29.15
+FI,ESPOO,"",60.22,24.67,193.184.164.219
+US,BATONROUGE,LA,30.4499,-91.1876,96.17.153.162
+FI,KAJAANI,"",64.23,27.68,193.184.164.219
+US,GROVERBEACH,CA,35.1287,-120.6191,23.216.10.54
+US,HUNTINGDON,PA,40.6074,-77.8631,23.192.161.16
+US,SIMIVALLEY,CA,34.2707,-118.7905,184.50.26.204
+US,BUTLER,PA,40.9096,-79.9361,65.121.209.127
+US,GARDENCITY,MI,42.3244,-83.3417,23.67.60.222
+IT,CAGLIARI,"",39.22,9.12,213.144.173.198
+MX,AGUASCALIENTES,AGU,21.88,-102.30,23.215.15.22
+US,OWASSO,OK,36.2942,-95.797,72.164.253.68
+TR,INKILAP,"",36.75,37.53,23.61.195.163
+US,DULUTH,MN,47.1196,-91.8629,23.63.227.227
+US,VALDOSTA,GA,30.7579,-83.3062,72.246.247.5
+US,PFLUGERVILLE,TX,30.4432,-97.5977,204.2.223.90
+US,EDMOND,OK,35.6833,-97.5261,23.63.227.227
+FI,VANTAA,"",60.30,24.85,82.96.58.102
+RU,KALUGA,"",54.54,36.27,80.239.217.238
+US,MENA,AR,34.5920,-94.1901,96.16.7.101
+ID,JOGJAKARTA,"",-7.80,110.37,23.0.162.40
+US,PEVELY,MO,38.2842,-90.4297,204.93.47.220
+US,WESTROXBURY,MA,42.2799,-71.1623,23.192.161.21
+PH,LEGASPI,"",15.82,120.60,202.78.83.170
+CN,YUETAN,AH,29.65,118.14,184.50.87.178
+US,HUMMELSTOWN,PA,40.2988,-76.709,23.192.161.30
+ID,TENGAH,"",-3.18,113.32,23.0.162.40
+UY,MONTEVIDEO,"",-34.88,-56.18,200.40.28.31
+BR,PELOTAS,RS,-31.77,-52.33,187.59.4.154
+GN,CONAKRY,"",9.51,-13.71,213.200.109.183
+KR,KIMCHON,"",36.12,128.12,125.56.214.149
+US,CORNING,NY,42.0806,-77.0397,209.18.41.23
+ML,BAMAKO,"",12.65,-8.00,81.52.201.82
+BY,GRODNO,"",53.68,23.83,80.239.222.190
+US,CORAOPOLIS,PA,40.5042,-80.1934,184.27.45.150
+CA,TROISRIVIERES,QC,46.35,-72.55,72.246.43.233
+US,SPARKS,NV,39.5386,-119.7498,23.216.10.78
+US,NORWICH,CT,41.5523,-72.0921,184.25.109.213
+US,HATTIESBURG,MS,31.1996,-89.2694,72.246.247.5
+US,CLIFTONHEIGHTS,PA,39.9228,-75.2984,184.28.17.76
+US,CENTRALIA,WA,46.7386,-122.9449,23.212.59.85
+US,JONESBORO,GA,33.5203,-84.3178,23.79.240.37
+JO,AMMAN,"",31.95,35.93,77.67.27.250
+US,MASSENA,NY,44.9476,-74.9244,107.14.38.217
+US,BRISTOL,VA,36.6927,-82.2134,209.48.37.188
+US,SAINTGEORGE,UT,37.1317,-113.7959,165.254.144.25
+US,CLAREMONT,CA,34.1276,-117.7153,173.223.52.70
+US,NEWBERG,OR,45.3226,-122.99,184.27.179.181
+US,MADERA,CA,36.9046,-120.1728,23.212.52.88
+AU,MARULAN,NSW,-34.70,150.02,202.7.177.87
+US,LAHABRA,CA,33.9421,-117.9517,23.216.10.54
+TR,KAYSERI,"",38.72,35.50,2.21.240.61
+US,CLINTONTOWNSHIP,MI,42.5574,-82.8963,23.67.60.222
+US,GLOBE,AZ,33.5677,-110.7249,63.226.34.174
+US,APACHEJUNCTION,AZ,33.4152,-111.5488,63.226.34.162
+DE,HAG,BW,47.73,7.92,2.16.217.211
+US,WAXHAW,NC,34.9191,-80.7283,209.18.41.23
+US,BEVERLYHILLS,CA,34.0738,-118.3994,63.141.193.62
+RU,KALININGRAD,"",55.92,37.88,2.21.240.40
+US,DELAWARE,OH,40.3029,-83.0602,107.14.38.227
+DE,OFFENBURG,BW,48.48,7.93,80.157.150.197
+US,CLEARFIELD,UT,41.1230,-112.0639,63.217.232.17
+US,PIKEVILLE,KY,37.5348,-82.513,184.27.45.157
+US,THIBODAUX,LA,29.8127,-90.7428,96.17.153.157
+US,LATHROP,CA,37.8212,-121.2919,96.17.12.48
+US,HAZEN,ND,47.3960,-101.6023,107.14.38.227
+AT,SALZBURG,"",47.80,13.03,195.145.147.108
+US,NEVADA,MO,37.8504,-94.3445,23.77.234.35
+US,DUMFRIES,VA,38.5915,-77.3508,184.28.17.76
+US,MACON,GA,32.8993,-83.468,184.51.35.226
+CN,SHENZHEN,GD,22.53,114.13,184.50.87.176
+US,KALAMA,WA,46.0150,-122.7836,192.80.13.117
+US,ROCKLIN,CA,38.8019,-121.2492,96.17.12.48
+US,WINTER,WI,45.8255,-90.8897,23.74.8.8
+US,SCHOOLCRAFT,MI,42.1212,-85.6839,23.74.8.24
+TN,TUNIS,"",36.80,10.18,46.33.70.213
+US,BERGENFIELD,NJ,40.9234,-73.9981,184.26.44.38
+FR,VITRYSURSEINE,"",48.78,2.40,2.16.117.200
+US,PEYTON,CO,39.0051,-104.5039,63.151.29.12
+PL,LUBLIN,"",51.25,22.57,2.22.52.101
+US,LAKEWALES,FL,27.8661,-81.4384,184.51.35.226
+US,POWAY,CA,32.9789,-117.0196,23.216.10.54
+FR,MONTOISON,"",44.78,4.92,2.16.117.190
+US,MONTCLAIR,CA,34.0753,-117.6972,184.50.26.179
+KR,MOKPO,"",34.79,126.39,61.111.58.229
+US,OWINGSMILLS,MD,39.4250,-76.7779,23.192.161.16
+FJ,SUVA,"",-18.13,178.42,104.72.70.95
+US,PORTERVILLE,CA,36.0318,-118.9656,23.216.10.78
+US,LINDEN,NJ,40.6259,-74.2395,23.67.242.156
+PL,KRASNIK,"",50.92,22.23,2.22.52.109
+US,DUNNELLON,FL,29.0187,-82.4395,23.33.186.134
+LB,BEIRUT,"",33.87,35.51,95.101.34.105
+DE,HEIDELBERG,BW,49.42,8.70,23.14.94.224
+KZ,TALDYKURGAN,"",45.00,77.92,2.20.142.173
+US,LAKEFOREST,CA,33.6490,-117.6848,184.50.26.179
+RU,IRKUTSK,"",52.27,104.33,217.212.227.31
+US,NEWBURYPARK,CA,34.1843,-118.9097,184.50.26.204
+US,MARINADELREY,CA,33.9786,-118.4476,184.50.26.204
+US,WETUMPKA,AL,32.5691,-86.1584,72.246.247.5
+US,NORTHTAZEWELL,VA,37.1608,-81.5125,107.14.43.30
+US,ALLENTOWN,PA,40.6019,-75.4727,184.29.107.38
+US,BAYSAINTLOUIS,MS,30.3134,-89.5231,96.17.153.157
+US,PEACHTREECITY,GA,33.3924,-84.5695,72.246.247.5
+US,ONEONTA,NY,42.4787,-75.0181,107.14.38.218
+US,HACIENDAHEIGHTS,CA,33.9955,-117.9764,107.14.44.212
+US,HARVEY,LA,29.8673,-90.069,96.17.153.162
+US,ELKTON,VA,38.3599,-78.6227,23.192.161.16
+US,ALBERTVILLE,AL,34.3010,-86.1927,72.246.247.5
+IE,CORK,"",51.90,-8.50,95.101.2.112
+US,DUBOIS,PA,41.1434,-78.731,184.26.44.38
+US,SOUTHHADLEY,MA,42.2564,-72.5775,165.254.202.96
+US,HATBORO,PA,40.1770,-75.1061,184.26.44.42
+NZ,NAENAE,"",-41.20,174.94,219.88.186.172
+ID,SEMARANG,"",-6.97,110.42,23.14.94.228
+US,SYRACUSE,NY,43.0499,-76.1506,107.14.38.227
+US,RIDGELAND,MS,32.4200,-90.1289,23.79.240.48
+US,NORTHAMPTON,MA,42.3230,-72.6707,184.25.109.213
+US,STOCKBRIDGE,GA,33.5641,-84.1952,23.79.240.36
+CZ,PLZEN,"",49.75,13.37,2.22.52.105
+PL,REDA,"",54.62,18.35,2.22.52.109
+US,BRIGHTON,CO,39.9758,-104.8092,23.212.53.75
+US,NEWPORT,AR,35.5678,-91.2073,23.5.164.143
+ES,OVIEDO,"",43.37,-5.83,80.149.168.111
+US,CANOGAPARK,CA,34.1977,-118.6018,184.87.195.109
+US,BENTON,KY,36.8777,-88.361,107.14.38.217
+US,MONTEREYPARK,CA,34.0511,-118.144,23.216.10.78
+US,LAMESA,CA,32.7605,-116.9997,184.50.26.194
+FI,YLIVIESKA,"",64.08,24.55,193.184.164.237
+HK,SHATIN,"",22.38,114.18,219.76.10.81
+BB,BRIDGETOWN,"",13.10,-59.62,23.74.2.7
+PL,ELBLAG,"",54.17,19.38,2.22.52.109
+US,COMPTON,CA,33.8794,-118.2368,184.50.26.201
+US,STATESBORO,GA,32.4474,-81.7452,184.27.45.157
+US,OAKDALE,CA,37.7848,-120.7726,96.17.12.48
+BR,GUARULHOS,SP,-23.47,-46.53,200.174.107.50
+FR,RENNES,"",48.08,-1.68,2.20.243.42
+IN,SION,MH,19.03,72.85,96.17.180.166
+US,DESTIN,FL,30.3934,-86.4958,184.51.35.226
+US,JENKS,OK,36.0001,-95.9806,23.215.15.32
+US,FORESTGROVE,OR,45.6684,-123.3405,184.27.179.181
+US,GREENCASTLE,IN,39.6767,-86.9214,23.63.227.227
+US,TAYLORVILLE,IL,39.5521,-89.3216,23.63.227.227
+MX,SANPEDROGARZAGARCIA,NLE,25.41,-99.91,184.26.93.116
+US,CONROE,TX,30.3059,-95.4359,204.2.223.91
+US,HYATTSVILLE,MD,38.9534,-76.9444,23.192.161.16
+JP,FUJITA,07,37.87,140.55,72.246.191.19
+US,ESPANOLA,NM,35.9775,-106.1582,63.216.54.229
+US,BULLHEADCITY,AZ,35.1469,-114.5576,23.5.164.146
+PL,KOLOBRZEG,"",54.18,15.58,2.22.52.101
+FR,ASNIERES,"",48.92,2.28,88.221.15.111
+US,STILLWATER,OK,36.0774,-97.0817,107.14.43.30
+US,GREELEY,CO,40.4475,-104.6861,184.84.180.68
+NZ,CHRISTCHURCH,"",-43.53,172.63,203.97.86.239
+US,LEESVILLE,LA,31.2063,-93.1344,204.2.223.90
+US,SCITUATE,MA,42.2010,-70.7631,184.26.44.42
+UA,ALUSHTA,CRIMEA,44.67,34.42,80.239.222.167
+US,VACAVILLE,CA,38.3470,-121.9283,165.254.45.13
+US,NEWHALL,CA,34.3744,-118.4762,184.50.26.194
+ID,DEPOK,"",-6.40,106.83,202.43.190.246
+US,HILO,HI,19.6686,-155.3062,165.254.96.248
+DE,NEUSS,NW,51.20,6.68,2.16.217.211
+US,LAJUNTA,CO,37.8368,-103.544,107.14.32.228
+DE,OLPE,NW,51.03,7.85,80.157.170.154
+ID,BOGOR,"",-6.15,106.98,23.0.162.54
+AU,WOLLONGONG,NSW,-34.43,150.88,23.62.157.32
+US,WOODSTOCK,GA,34.1201,-84.4649,23.212.53.64
+US,SILVERDALE,WA,47.7228,-122.7145,23.212.59.63
+US,SMITHFIELD,UT,41.8466,-111.898,184.84.180.101
+US,ABILENE,TX,32.4816,-99.6841,23.5.164.146
+PR,GUAYNABO,"",18.3658,-66.0928,72.246.65.26
+GB,EXETER,EN,50.70,-3.53,88.221.87.94
+US,LAGRANGE,GA,33.0069,-85.1034,23.79.240.36
+US,ARCADIA,CA,34.1380,-118.0283,165.254.144.25
+US,RIVERBANK,CA,37.7323,-120.941,96.17.12.44
+DE,TRAUBING,BY,47.95,11.27,195.145.147.107
+US,MONTEVISTA,CO,37.5196,-106.1764,107.14.32.228
+US,ALISOVIEJO,CA,33.5767,-117.7127,63.151.119.16
+US,SAINTCLOUD,FL,28.2446,-81.2943,23.33.186.101
+US,WESTMIFFLIN,PA,40.3582,-79.9065,23.192.161.16
+DE,KEMPTEN,BY,47.72,10.32,194.25.95.214
+US,BATAVIA,NY,42.9969,-78.2158,107.14.38.224
+MX,CULIACAN,SIN,24.00,-107.03,173.223.52.70
+US,POCATELLO,ID,42.8976,-112.3706,65.116.149.89
+EE,TARTU,"",58.37,26.74,82.96.58.102
+JP,KANDA,07,37.20,140.38,202.229.2.213
+US,BAYSIDE,NY,40.7918,-73.7759,184.26.44.38
+US,BUFORD,GA,34.1046,-84.0037,23.79.240.37
+RU,KIROV,"",54.83,36.47,80.239.222.190
+US,ROWLANDHEIGHTS,CA,33.9850,-117.9013,184.50.26.204
+US,CULLOWHEE,NC,35.2608,-83.1173,184.27.45.157
+US,AUBURN,AL,32.6014,-85.5082,204.2.243.135
+DE,KRONBERG,HE,50.18,8.50,92.122.188.163
+AU,IPSWICH,QLD,-27.62,152.77,23.62.157.32
+SE,GAVLE,X,60.67,17.17,213.155.156.207
+US,METAIRIE,LA,29.9840,-90.1664,96.17.153.157
+US,HERCULES,CA,38.0074,-122.2624,23.212.52.79
+US,PRESCOTT,AZ,34.7884,-112.8659,63.226.34.176
+US,SAYRE,PA,41.9771,-76.4144,107.14.38.217
+FR,NOISYLEGRAND,"",48.85,2.57,2.16.117.190
+US,TAPPAHANNOCK,VA,37.9112,-76.9715,208.185.55.86
+ID,YOGYAKARTA,"",-7.80,110.37,23.0.162.40
+FR,LOGNES,"",48.83,2.62,2.16.117.200
+PL,SZCZECIN,"",51.92,19.72,80.239.222.169
+US,ARANSASPASS,TX,27.9093,-97.1497,23.215.15.9
+ID,PALEMBANG,"",-2.92,104.75,96.17.180.177
+US,LAREDO,TX,27.5137,-99.5021,23.5.164.146
+US,QUAKERTOWN,PA,40.4606,-75.3304,184.26.44.42
+GB,ALFRETON,EN,53.10,-1.38,195.245.125.114
+CA,HINTON,AB,53.40,-117.58,24.244.17.205
+US,SEWARD,NE,40.8874,-97.126,107.14.43.30
+PL,WROCLAW,"",51.10,17.03,2.22.61.102
+US,SANTACLARITA,CA,34.5130,-118.4027,184.50.26.204
+US,AVON,CO,39.5815,-106.4966,184.84.180.68
+KZ,BELOUSOVKA,"",50.13,82.52,2.21.240.40
+IN,CHANDIGARH,CH,30.74,76.79,117.239.91.75
+US,CROSBY,TX,29.9299,-95.0527,23.212.53.75
+CN,QIAOTOU,ZJ,30.15,121.36,23.15.10.112
+US,FLORA,IL,38.6705,-88.5031,23.74.8.8
+DE,KIEL,SH,54.33,10.13,194.25.95.225
+RU,OMSK,"",55.00,73.40,2.21.240.61
+US,PALMCITY,FL,27.1320,-80.3491,23.79.240.48
+US,NEEDHAM,MA,42.2750,-71.2465,184.25.109.200
+US,CHARLESTON,WV,38.3510,-81.6265,184.27.45.157
+US,CENTERCONWAY,NH,43.9597,-71.0453,165.254.35.197
+US,VALLEY,AL,32.7858,-85.1946,23.79.240.36
+US,FRENCHCAMP,CA,37.8805,-121.2989,23.212.52.88
+US,STUDIOCITY,CA,34.1386,-118.3879,107.14.44.185
+DE,KONSTANZ,BW,47.67,9.18,194.25.95.225
+US,URBANDALE,IA,41.6320,-93.7353,65.113.249.8
+US,AUSTELL,GA,33.8340,-84.6343,72.246.247.5
+US,NEWCASTLE,DE,39.6483,-75.6041,23.192.161.30
+RU,TYUMEN,"",58.52,48.27,80.239.237.84
+US,BELMAR,NJ,40.1783,-74.0222,184.51.125.79
+FR,AMBERIEUENBUGEY,"",45.92,4.73,2.16.117.200
+US,ORANGEVALE,CA,38.6892,-121.2198,23.212.52.82
+US,BROKENARROW,OK,35.9842,-95.8102,63.216.54.229
+FR,ALFORTVILLE,"",48.80,2.42,2.16.117.190
+US,BLOOMSBURG,PA,41.0301,-76.4558,23.67.242.139
+US,FERNDALE,WA,48.8653,-122.6362,23.212.59.64
+US,MORGANTOWN,WV,39.5846,-79.9182,23.192.161.16
+VN,BINHTHANH,"",10.77,106.75,96.17.180.177
+IN,LUDHIANA,PB,30.90,75.85,23.211.135.66
+AR,ROSARIO,"",-32.95,-60.67,200.123.201.215
+RU,GRAN,"",50.72,39.78,80.239.217.231
+US,WATERLOO,IL,38.3034,-90.1358,23.63.227.227
+CA,COURTENAY,BC,49.68,-125.00,184.27.179.187
+US,LEWISBURG,WV,37.8469,-80.447,184.28.17.55
+US,ELMWOODPARK,NJ,40.9049,-74.1196,23.67.242.156
+US,JOPLIN,MO,37.1074,-94.5218,23.215.15.9
+ID,BARAT,"",-7.57,111.45,202.43.190.246
+US,PHOENIXVILLE,PA,40.1221,-75.5397,23.192.161.16
+US,GRETNA,LA,29.9128,-90.0524,23.215.15.22
+US,SHEFFIELDLAKE,OH,41.4650,-82.0929,107.14.32.235
+US,SILVERSPRING,MD,39.0245,-77.0094,96.6.47.120
+CA,REDDEER,AB,52.27,-113.80,184.27.179.187
+US,MORTONGROVE,IL,42.0422,-87.789,23.67.60.223
+ZA,ISANDO,"",-26.15,28.20,41.193.163.45
+US,HAINESCITY,FL,28.0703,-81.5695,192.204.11.244
+JP,OKI,33,34.62,134.13,72.246.184.92
+US,KINGSPORT,TN,36.4877,-82.6162,184.29.107.20
+US,CASTLEROCK,CO,39.3765,-104.8554,184.84.180.92
+US,CENTEREACH,NY,40.8699,-73.0833,184.26.44.42
+TR,DIYARBAKIR,"",37.92,40.23,193.45.15.199
+AR,LARIOJA,"",-29.43,-66.85,190.98.167.220
+US,OROVILLE,CA,39.5324,-121.6485,63.151.119.25
+FR,LIGNE,"",50.67,2.33,23.67.255.158
+DZ,ALGIERS,"",36.76,3.05,213.200.109.183
+US,TUPELO,MS,34.2235,-88.7398,23.220.100.223
+US,RACINE,WI,42.7263,-87.7829,165.254.96.242
+CN,TAIZHOU,ZJ,28.85,121.12,72.246.191.19
+US,OREGONCITY,OR,45.3306,-122.529,23.212.59.85
+PL,LODZ,"",51.75,19.47,80.239.222.169
+US,BROWNSBURG,IN,39.8655,-86.3812,65.113.249.8
+MX,GUAYMAS,SON,27.93,-110.90,173.223.52.70
+US,DOUGLASVILLE,GA,33.7516,-84.7478,23.79.240.37
+US,SUISUNCITY,CA,38.2546,-122.0486,23.212.52.88
+US,HALETHORPE,MD,39.2187,-76.722,23.192.161.16
+US,MIDDLETON,ID,43.7467,-116.5805,192.80.13.108
+US,NEWBEDFORD,MA,41.6384,-70.9419,184.25.109.196
+CA,SAINTLAURENT,QC,45.52,-73.67,72.246.43.237
+US,PORTCHARLOTTE,FL,26.9751,-82.152,23.79.240.36
+US,MIDDLERIVER,MD,39.3459,-76.3996,23.192.161.21
+US,VERONA,NJ,40.8330,-74.2435,23.74.8.24
+BR,CAMPINAS,SP,-22.90,-47.08,200.174.107.42
+US,TOPEKA,KS,39.0486,-95.6778,23.77.234.35
+GB,BRENT,EN,51.55,-0.27,92.122.126.82
+US,YORKTOWN,VA,37.2346,-76.5585,23.220.148.108
+US,SANLUIS,AZ,32.4906,-114.7753,184.50.26.201
+ID,MAKASSAR,"",2.45,99.78,118.98.42.129
+US,QUINLAN,TX,32.9155,-96.1709,107.14.43.30
+US,LINDALE,GA,34.1582,-85.1905,23.79.240.37
+US,CEDARPARK,TX,30.4956,-97.8267,23.215.15.9
+KR,TAEJON,"",36.32,127.42,183.111.23.63
+PL,GOGOLIN,"",53.40,18.67,2.22.52.109
+PH,MANDALUYONG,"",14.58,121.03,120.28.5.110
+US,WARRINGTON,PA,40.2476,-75.1421,23.67.242.139
+CZ,BLANSKO,"",50.70,14.10,195.27.155.188
+IN,BHUBANESHWAR,OR,20.23,85.83,23.57.76.20
+US,WARWICK,NY,41.2642,-74.3694,184.51.125.79
+US,AMERICANFORK,UT,40.4102,-111.814,184.84.180.101
+US,OXNARD,CA,34.2254,-119.1713,23.216.10.78
+MX,MAZATLAN,SIN,23.22,-106.42,173.223.52.67
+US,HAGERSTOWN,MD,39.6364,-77.7249,168.143.243.33
+US,URBANA,IL,40.1590,-88.187,23.63.227.214
+US,SUMMERFIELD,FL,28.9926,-82.0497,23.79.240.48
+US,HAMMOND,IN,41.6065,-87.4967,23.67.60.222
+US,MOAB,UT,38.6903,-109.2562,184.85.249.14
+JP,IWAMI,28,34.78,134.53,23.3.74.113
+US,GALVESTON,TX,29.3093,-94.7816,23.212.53.75
+US,COALTOWNSHIP,PA,40.7855,-76.5082,184.26.44.38
+US,LUBBOCK,TX,33.5838,-101.8403,23.5.164.143
+US,HAUGHTON,LA,32.5391,-93.5257,96.17.153.162
+PS,GAZA,"",31.50,34.47,95.100.169.105
+US,TALLAHASSEE,FL,30.4294,-84.2579,69.31.132.229
+PL,OSIELSKO,"",53.18,18.07,80.239.222.190
+US,LAGRANDE,OR,45.2284,-118.272,165.254.1.165
+US,WOODBURN,OR,45.1385,-122.8359,184.27.179.159
+US,HOLBROOK,NY,40.7951,-73.0765,184.26.44.38
+LV,CESIS,"",57.30,25.25,213.155.156.206
+US,FORTHUACHUCA,AZ,31.5925,-110.3847,204.94.155.235
+US,MOUNTAINHOMEAFB,ID,43.0653,-116.032,206.104.149.146
+US,HAVERFORD,PA,40.0078,-75.3135,184.26.44.35
+US,MECHANICSBURG,PA,40.2485,-77.0142,23.67.242.156
+US,PARSIPPANY,NJ,40.8553,-74.3996,184.51.125.68
+US,GREENBAY,WI,44.4814,-88.0196,23.63.227.214
+YE,SANA,"",15.35,44.21,79.140.94.183
+US,BESSEMER,AL,33.4077,-86.9494,204.2.243.132
+MX,ZAPOPAN,JAL,20.72,-103.40,23.215.15.9
+US,OGDEN,UT,41.2234,-111.9731,23.61.195.165
+US,GRANITECITY,IL,38.7259,-90.0982,69.31.97.120
+US,MUNCIE,IN,40.1286,-85.3767,204.93.47.220
+US,KNOXVILLE,TN,35.9646,-83.9197,23.79.240.37
+US,APPLEVALLEY,CA,34.5744,-117.1146,63.233.61.151
+US,SHEBOYGAN,WI,43.7072,-87.7387,23.63.227.227
+US,SCHAUMBURG,IL,42.0334,-88.0833,107.14.38.224
+BR,GOIANIA,GO,-16.67,-49.27,200.174.107.42
+US,HERKIMER,NY,43.0566,-75.0112,107.14.38.218
+NL,DELFT,"",52.00,4.37,2.16.153.173
+TW,CHIAI,"",23.48,120.44,61.220.62.175
+US,DEPERE,WI,44.4310,-88.1738,107.14.38.218
+US,SOUDERTON,PA,40.2970,-75.3345,184.26.44.42
+US,MONTVILLE,CT,41.4628,-72.1545,165.254.48.150
+RO,RAMNICUVALCEA,"",45.10,24.37,81.196.26.237
+AT,ETZELSDORF,"",47.95,14.05,195.145.147.108
+US,SIMPSONVILLE,SC,34.6913,-82.2915,23.79.240.37
+CA,FORTMCMURRAY,AB,56.73,-111.38,24.244.17.197
+US,CARSONCITY,NV,39.1386,-119.6595,23.216.10.78
+PH,DILIMAN,"",14.63,121.07,202.78.83.175
+US,CAPECANAVERAL,FL,28.3971,-80.6086,96.6.47.106
+US,SOMERVILLE,MA,42.3814,-71.0971,184.29.107.20
+CN,QUANZHOU,FJ,24.90,118.58,184.50.87.178
+GB,BASILDON,EN,51.57,0.47,23.67.255.158
+KW,KUWAIT,"",29.37,47.98,63.80.12.225
+US,DOWNERSGROVE,IL,41.8086,-88.0231,23.215.15.9
+US,YORKSHIRE,NY,42.5238,-78.4755,184.26.44.42
+FR,BEZONS,"",48.93,2.22,2.16.117.190
+US,WARMINSTER,PA,40.2185,-75.0735,23.192.161.16
+US,HERRIMAN,UT,40.4909,-112.0097,23.61.195.163
+US,MONTEBELLO,CA,34.0167,-118.1107,63.151.119.25
+US,DAYTONABEACH,FL,29.1935,-81.0536,184.51.145.22
+US,LACEY,WA,47.0254,-122.7992,23.212.59.63
+CM,YAOUNDE,"",3.87,11.52,184.84.239.175
+US,BRYNMAWR,PA,40.0226,-75.3301,23.67.242.139
+US,OWENSBORO,KY,37.7353,-87.2433,107.14.38.218
+JP,KUMAGAYA,11,36.13,139.38,202.239.172.94
+US,EGGHARBORTOWNSHIP,NJ,39.3650,-74.6283,184.26.44.38
+RU,BARNAUL,"",55.65,66.27,2.21.240.40
+PL,BYTOM,"",50.35,18.97,2.22.52.105
+CN,HARBIN,HL,45.75,126.65,72.246.191.19
+US,PLYMOUTH,IN,41.3572,-86.3281,23.67.60.223
+US,LEANDER,TX,30.5580,-97.9247,184.28.23.24
+IN,NIWAS,MP,23.05,80.43,124.124.252.153
+BY,VITEBSK,"",55.19,30.19,92.122.189.114
+US,EVANSVILLE,IN,37.9744,-87.5555,23.63.227.227
+JP,KAGOSHIMA,46,31.60,130.55,202.229.2.212
+US,JAMAICA,NY,40.6917,-73.8061,209.18.41.27
+ZA,NORTHCLIFF,"",-26.13,27.95,165.165.46.37
+DE,POTSDAM,BB,52.40,13.07,195.95.193.150
+JP,CHIBA,12,35.60,140.12,104.74.70.98
+US,NORTHFIELD,MN,44.4726,-93.1785,184.85.215.170
+US,BRENHAM,TX,30.2352,-96.4076,204.2.223.91
+US,MONTROSE,CA,34.2114,-118.231,23.216.10.54
+US,SNYDER,TX,33.0123,-100.8338,23.215.15.9
+ID,BARU,"",-6.13,106.78,23.0.162.40
+US,JOHNSONCITY,TN,36.3400,-82.3328,23.79.240.36
+US,FORTWALTONBEACH,FL,30.4494,-86.6242,183.111.23.63
+AE,ABUDHABI,"",24.47,54.37,23.5.164.146
+JP,NIIGATA,15,37.92,139.05,117.104.139.162
+US,JASPER,GA,34.4645,-84.4746,184.28.127.58
+US,TALLMADGE,OH,41.1018,-81.4225,107.14.38.217
+CA,BOWMANVILLE,ON,43.90,-78.68,72.246.43.232
+TR,ULUS,"",39.93,32.87,193.45.15.198
+US,GLENELLYN,IL,41.8564,-88.062,23.67.60.220
+US,ANDERSON,IN,40.1325,-85.7642,65.113.249.11
+US,WEXFORD,PA,40.6275,-80.0614,72.246.52.107
+US,NICEVILLE,FL,30.4944,-86.0572,184.51.35.226
+US,DEARBORN,MI,42.3055,-83.1724,63.141.200.241
+US,EASTLIVERPOOL,OH,40.6788,-80.5838,23.192.161.21
+US,NEWPORTBEACH,CA,33.6187,-117.9283,23.215.15.22
+US,DEBARY,FL,28.8805,-81.3193,23.212.53.75
+BY,MOGILEV,"",53.91,30.34,23.14.94.224
+US,NORCROSS,GA,33.9378,-84.2013,72.246.247.30
+RU,KAZAN,"",55.75,49.13,2.21.240.61
+RO,SIBIU,"",45.80,24.15,81.196.26.231
+CZ,FRENSTATPODRADHOSTEM,"",49.55,18.22,23.62.237.133
+CN,HAIKOU,HI,20.05,110.34,72.246.191.19
+US,SOUTHRICHMONDHILL,NY,40.6884,-73.8234,184.26.44.42
+US,EDMONDS,WA,47.8000,-122.3719,23.212.59.63
+US,WINCHESTER,TN,35.1786,-86.12,23.212.53.64
+US,CENTRALPOINT,OR,42.4072,-122.9556,192.80.13.117
+US,JESUP,GA,31.5041,-81.8277,23.79.240.48
+US,ALIEF,TX,29.7106,-95.5963,23.212.53.64
+JP,UJI,26,34.88,135.80,23.3.74.112
+JP,TAMA,33,34.48,133.93,118.155.230.132
+US,ELMENDORFAFB,AK,61.2646,-149.8047,23.212.59.85
+IN,JAISALMER,RJ,26.92,70.90,184.25.157.169
+US,MUKILTEO,WA,47.9095,-122.3022,23.212.59.85
+US,HOBOKEN,NJ,40.7453,-74.032,23.67.242.139
+DE,EBERSWALDE,BB,52.83,13.83,92.122.207.179
+US,YUMA,AZ,32.7006,-114.6726,184.50.26.179
+US,HYDEN,KY,37.1647,-83.4362,184.51.35.226
+US,ARDMORE,PA,40.0021,-75.2992,23.67.242.139
+US,CEDARHILL,TX,32.5815,-96.9616,107.14.43.30
+RU,TIS,"",57.01,57.60,80.239.217.231
+US,UNION,NJ,40.6941,-74.2694,184.26.44.38
+US,BELLEVILLE,IL,38.4985,-89.9796,204.93.47.216
+IT,BOLZANO,"",46.52,11.37,213.144.173.218
+US,NOBLE,OK,35.1418,-97.2907,64.129.104.135
+US,HUTCHINSON,KS,38.0313,-98.1636,23.215.15.22
+US,PULASKI,VA,37.0726,-80.7961,184.26.44.40
+CY,LEMESOS,"",34.67,33.03,2.20.142.173
+BG,KLIMENT,"",42.60,24.68,80.239.222.167
+DE,BRANDENBURG,BB,52.42,12.55,80.157.150.169
+US,ORMONDBEACH,FL,29.2856,-81.0563,184.51.145.7
+US,WOODSIDE,NY,40.7439,-73.9053,184.29.107.20
+US,OREGON,OH,41.6550,-83.4472,23.74.8.24
+US,FORTMOHAVE,AZ,35.0028,-114.5797,24.143.194.216
+IR,KERMANSHAH,"",34.31,47.06,213.155.156.212
+US,NOBLESVILLE,IN,40.0583,-85.9657,23.67.60.222
+RU,ZHIGULI,"",53.35,49.30,2.21.240.40
+US,CHAMPLIN,MN,45.1692,-93.3912,23.67.60.223
+US,DELANO,CA,35.7580,-119.1095,184.87.195.109
+CY,PAPHOS,"",34.77,32.42,173.223.52.70
+US,SALIDA,CA,37.7163,-121.0942,23.216.10.54
+US,BENSENVILLE,IL,41.9552,-87.9401,107.14.38.224
+US,LONGMONT,CO,40.1771,-105.0797,184.84.180.92
+US,PROVO,UT,40.2247,-111.6938,63.80.12.225
+JP,YAMAGUCHI,35,34.17,131.48,184.51.199.132
+AU,PENNANTHILLS,NSW,-33.73,151.07,23.205.116.7
+US,STATESVILLE,NC,35.7886,-80.8801,96.16.12.216
+US,NORTHAURORA,IL,41.8068,-88.3366,23.67.60.223
+US,BEAR,DE,39.5786,-75.7006,184.26.44.38
+AU,LIVERPOOL,NSW,-33.90,150.93,23.62.8.25
+US,CLAREMORE,OK,36.3346,-95.5666,23.215.15.22
+DE,BAUMGARTEN,BY,50.15,11.47,80.157.150.192
+US,CHATTANOOGA,TN,35.0459,-85.3097,184.51.35.215
+US,GRAPEVINE,TX,32.9275,-97.0735,192.204.11.244
+US,AMES,IA,42.0383,-93.6284,204.93.47.216
+RO,GALATI,"",45.85,24.97,2.22.52.102
+US,ACWORTH,GA,34.0445,-84.7171,23.79.240.37
+US,GOLDSBORO,NC,35.4141,-78.0215,209.18.41.23
+ID,SURABAYA,"",-4.67,105.72,118.98.37.99
+US,GALLUP,NM,35.4315,-108.7243,63.226.34.173
+US,UPLAND,CA,34.1381,-117.6589,23.216.10.78
+US,OAKPARK,CA,34.1839,-118.7702,184.50.26.179
+US,CALABASAS,CA,34.1257,-118.6769,184.50.26.179
+IT,COMO,"",45.78,9.08,213.144.173.218
+US,MUSCLESHOALS,AL,34.7605,-87.6264,72.246.247.30
+US,BAUDETTE,MN,48.5595,-94.661,23.212.53.75
+US,LAWRENCEBURG,IN,39.1597,-84.8764,23.74.8.8
+US,KENMORE,WA,47.7577,-122.2428,23.212.59.85
+US,DELAND,FL,28.9706,-81.4214,184.51.145.22
+US,COMSTOCKPARK,MI,43.0682,-85.6853,65.113.249.8
+HT,PETIONVILLE,"",18.51,-72.29,23.74.2.7
+US,CHICO,CA,39.9285,-121.8223,184.84.180.101
+RO,BRAILA,"",45.27,27.98,81.196.26.231
+US,TINLEYPARK,IL,41.5679,-87.7949,23.67.60.222
+RU,FRYAZINO,"",55.96,38.05,213.155.156.212
+US,FALLRIVER,MA,41.7314,-71.1164,184.25.109.196
+US,SAINTJOSEPH,MO,39.7657,-94.8425,23.5.164.143
+SA,ALKHOBAR,"",26.28,50.21,79.140.94.183
+US,MONMOUTH,OR,44.7727,-123.3556,192.80.13.117
+US,GLENSIDE,PA,40.1012,-75.1722,23.67.242.156
+US,RESTON,VA,38.9597,-77.3374,65.121.209.125
+RU,EKATERINBURG,"",56.85,60.60,2.21.240.61
+US,PENSACOLA,FL,30.4205,-87.2234,184.51.35.226
+US,ADAMSVILLE,AL,33.5928,-86.9876,23.220.100.223
+PL,DEBICA,"",51.65,22.57,80.239.222.169
+US,ALAMOGORDO,NM,32.7929,-106.161,63.226.34.176
+IT,SAVONA,"",44.28,8.50,213.144.173.218
+US,SOUTHELGIN,IL,41.9935,-88.277,107.14.38.218
+US,GOODYEAR,AZ,33.4238,-112.4015,63.226.34.176
+US,KENNESAW,GA,34.0374,-84.5922,72.246.247.5
+DZ,CONSTANTINE,"",36.37,6.61,79.140.94.183
+IN,JAIPUR,RJ,26.92,75.82,96.17.182.136
+US,ANNANDALEONHUDSON,NY,42.0124,-73.8998,184.29.107.20
+US,CARPINTERIA,CA,34.6066,-119.5558,173.223.52.70
+US,GAINESVILLE,GA,34.3157,-83.8152,23.79.240.37
+US,LANSDALE,PA,40.2305,-75.2995,23.77.238.9
+YE,SANAA,"",15.35,44.21,184.84.180.98
+NL,THEHAGUE,"",52.08,4.30,92.122.189.114
+US,KINGFISHER,OK,35.9153,-98.0257,174.76.226.117
+US,DOVER,NH,43.1854,-70.9128,184.25.109.213
+PR,MAYAGUEZ,"",18.1211,-67.0824,64.86.201.118
+US,ZION,IL,42.4565,-87.8597,107.14.38.218
+US,SEYMOUR,CT,41.3811,-73.0868,184.25.109.196
+DE,DEGGENDORF,BY,48.83,12.97,84.53.146.39
+VE,MARACAIBO,"",10.63,-71.64,72.246.65.37
+US,VALLEYVILLAGE,CA,34.1666,-118.3996,184.50.26.179
+AT,INNSBRUCK,"",47.27,11.40,95.100.169.112
+US,MORRIS,IL,41.3973,-88.4715,23.67.60.223
+US,BANNING,CA,33.9464,-116.8543,23.216.10.78
+US,VINELAND,NJ,39.5016,-75.0264,184.26.44.38
+UA,TERNOPOL,"",49.55,25.58,23.14.94.220
+IN,BALAJINAGAR,TN,13.12,80.23,96.17.180.166
+US,BOUNTIFUL,UT,40.8715,-111.8314,23.61.195.160
+FR,RUEILMALMAISON,"",48.88,2.20,2.16.117.200
+US,PITTSFORD,NY,43.0476,-77.5243,23.79.240.36
+KR,KWANGJU,"",35.15,126.92,23.65.188.30
+US,TRAVISAFB,CA,38.2626,-121.9405,63.217.232.22
+US,BONIFAY,FL,30.8908,-85.6931,2.21.240.61
+GB,COSHAM,EN,50.83,-1.07,23.67.255.158
+US,JANESVILLE,WI,42.6846,-89.1369,184.85.215.165
+JP,FUKUOKA,40,33.58,130.40,117.104.139.162
+NZ,TIMARU,"",-44.40,171.25,219.88.186.164
+MM,RANGOON,"",16.78,96.17,96.17.180.166
+US,NORTHLASVEGAS,NV,36.2132,-115.1197,65.116.149.89
+US,PORTRICHEY,FL,28.3040,-82.7021,23.33.186.134
+US,PAINTSVILLE,KY,37.7517,-82.9074,184.28.17.76
+US,LIVEOAK,FL,30.2764,-83.0529,23.79.240.37
+US,POPLARBLUFF,MO,36.7803,-90.4373,23.63.227.227
+BE,LIEGE,"",50.63,5.57,2.18.243.1
+US,FORTLEE,NJ,40.8502,-73.9734,184.26.44.38
+RO,IP,"",47.23,22.65,80.239.222.169
+US,LEOMINSTER,MA,42.5209,-71.7716,184.25.109.201
+US,CHILLICOTHE,OH,39.3125,-83.0274,107.14.38.224
+US,SAINTPAULPARK,MN,44.8338,-92.9932,63.151.29.12
+PL,GDANSK,"",54.35,18.67,2.22.52.102
+US,WYNNE,AR,35.2584,-90.8369,173.197.194.166
+US,CASSELBERRY,FL,28.6630,-81.3122,23.33.186.101
+US,PIKESVILLE,MD,39.3860,-76.7222,96.6.47.120
+TW,TAOYUAN,"",24.27,121.25,203.69.138.118
+AT,HEIDENREICHSTEIN,"",48.87,15.12,195.145.147.108
+CN,HUAIHUA,HN,27.55,109.95,72.246.191.16
+RU,LENIN,"",48.30,40.88,213.248.108.233
+US,WINNETKA,CA,34.2090,-118.5753,184.87.195.99
+US,STIGLER,OK,35.2928,-95.0844,174.76.226.110
+US,GREENCOVESPRINGS,FL,29.9530,-81.7369,184.51.145.7
+AR,MARGARITA,"",-31.70,-61.65,190.98.167.220
+US,CLEMENTON,NJ,39.8055,-74.9997,184.26.44.38
+US,DARBY,PA,39.9168,-75.2677,184.26.44.40
+US,CARLYLE,IL,38.5905,-89.3709,23.63.227.214
+RU,IZHEVSK,"",56.85,53.23,92.122.215.67
+US,RANCHOCORDOVA,CA,38.5857,-121.2825,96.17.12.44
+US,WATERTOWN,MA,42.3708,-71.1833,184.29.107.20
+US,KEARNEY,NE,40.7317,-98.9983,184.85.215.165
+AU,BRAESIDE,VIC,-37.98,145.12,184.84.221.116
+GQ,MALABO,"",3.75,8.78,2.20.44.118
+US,TWENTYNINEPALMS,CA,34.1466,-115.8753,184.50.26.179
+RW,KIGALI,"",-1.96,30.04,41.193.163.45
+US,LAMIRADA,CA,33.9172,-118.0114,184.50.26.179
+US,HOTSPRINGSNATIONALPARK,AR,34.5331,-93.0035,66.171.227.82
+US,STERLINGHEIGHTS,MI,42.5651,-83.0651,23.67.60.222
+DE,LUE,BY,49.58,12.15,2.16.217.211
+US,JOHNSTOWN,PA,40.3358,-78.9111,23.192.161.16
+US,PAOLI,PA,40.0429,-75.48,23.67.242.139
+US,BLAIR,NE,41.5565,-96.2448,23.79.255.149
+US,HUNTERSVILLE,NC,35.4108,-80.8434,209.18.41.27
+TH,NAKHONRATCHASIMA,"",14.97,102.12,61.19.12.164
+AU,BUNBURY,WA,-33.33,115.63,202.7.177.76
+GB,BROMSGROVE,EN,52.33,-2.07,23.67.255.158
+DE,HALLE,ST,51.50,12.00,80.157.150.192
+CU,HAVANA,"",23.13,-82.36,72.246.65.38
+US,FONDDULAC,WI,43.7436,-88.3886,184.85.215.165
+US,ORCHARDPARK,NY,42.7477,-78.7413,107.14.38.227
+CN,JIAXING,ZJ,30.77,120.75,72.246.191.19
+US,EDINBURG,TX,26.3620,-98.1616,184.26.93.116
+US,SHAWANO,WI,44.7924,-88.6722,23.74.8.24
+US,COTTONWOOD,AZ,34.6334,-112.1256,63.226.34.174
+CN,XINING,QH,36.62,101.77,72.246.191.19
+US,VENTURA,CA,34.3488,-119.3304,23.216.10.54
+US,HILLSBOROUGH,NJ,40.4995,-74.629,184.26.44.38
+US,PRYOR,OK,36.2697,-95.3138,165.254.138.165
+US,LAKEZURICH,IL,42.2010,-88.0504,107.14.38.224
+US,LAPLACE,LA,30.1499,-90.4621,184.84.180.68
+US,FEASTERVILLETREVOSE,PA,40.1496,-74.9856,23.67.242.139
+US,YONKERS,NY,40.9431,-73.8809,184.51.125.68
+US,BENTONHARBOR,MI,42.1150,-86.3578,96.17.9.8
+GB,CARDIFF,WA,51.50,-3.20,184.27.139.24
+US,BLUERIDGE,GA,34.7762,-84.2671,184.28.127.55
+US,BREMERTON,WA,47.5964,-122.6209,23.212.59.85
+IN,RAJAHMUNDRY,AP,16.98,81.78,23.57.69.157
+US,HACKETTSTOWN,NJ,40.8661,-74.8361,184.26.44.38
+US,SANFERNANDO,CA,34.2870,-118.435,184.50.26.179
+US,ODELL,OR,45.5565,-121.4733,184.27.179.187
+US,TWINFALLS,ID,42.2444,-114.6624,192.80.13.108
+SR,PARAMARIBO,"",5.83,-55.17,23.74.2.12
+RU,STAVROPOL,"",53.52,49.41,2.21.240.40
+US,SEFFNER,FL,27.9906,-82.2811,23.33.186.101
+AM,EREVAN,"",40.18,44.50,80.239.237.230
+CN,WUZHOU,GX,23.48,111.32,192.80.13.108
+IT,BOLOGNA,"",44.48,11.33,2.18.240.95
+US,PAWTUCKET,RI,41.8706,-71.3891,72.246.43.237
+JP,TAISEI,17,36.45,136.47,23.3.104.16
+IT,ALESSANDRIA,"",44.90,8.62,195.22.200.243
+GB,BAGULEY,EN,53.38,-2.25,88.221.87.112
+US,SAINTJOHNS,AZ,34.4981,-109.2419,184.85.249.14
+US,ATASCADERO,CA,35.4482,-120.6696,23.216.10.54
+DE,HAU,NW,51.15,6.27,23.14.94.220
+US,SHELBYVILLE,TN,35.4645,-86.4889,23.79.240.36
+CA,SCARBOROUGH,ON,43.75,-79.20,192.204.11.226
+US,GENESEO,NY,42.7919,-77.7757,107.14.38.217
+US,PERRYSBURG,OH,41.5209,-83.5671,23.74.8.8
+US,SANTANVALLEY,AZ,33.3064,-111.8406,23.5.164.143
+DE,HAUPT,NW,51.80,8.62,2.20.142.166
+DE,SCHWEDT,BB,53.07,14.30,92.122.207.164
+TZ,DARESSALAAM,"",-6.80,39.28,92.122.127.109
+FR,CHAMBERY,"",45.57,5.93,88.221.83.122
+US,SPARTA,IL,38.1133,-89.7153,23.63.227.227
+CA,GRANDEPRAIRIE,AB,55.17,-118.80,184.27.179.165
+US,STURGEONBAY,WI,44.7888,-87.4464,184.85.215.165
+US,SALINAS,CA,36.6625,-121.6487,69.22.154.219
+JP,OKINAWA,47,26.34,127.80,184.51.199.145
+US,WHITEFISH,MT,48.5029,-114.5829,107.14.32.228
+BR,BARRAMANSA,RJ,-22.53,-44.18,200.174.107.50
+US,NAMPA,ID,43.5891,-116.6159,192.80.13.108
+MX,MORELIA,MIC,19.70,-101.12,23.215.15.22
+US,ADRIAN,MI,41.9076,-84.0644,165.254.207.111
+US,BOAZ,AL,34.2012,-86.1667,23.79.240.36
+US,GARLAND,TX,32.9284,-96.6206,23.215.15.22
+PH,PAMPANGA,"",15.18,120.54,23.2.16.104
+CZ,KARVINA,"",49.87,18.55,23.74.24.69
+US,SAVANNAH,GA,32.0721,-81.0952,72.246.247.5
+US,PAMPA,TX,35.4253,-100.8386,23.215.15.9
+HN,TEGUCIGALPA,"",14.10,-87.22,165.254.205.13
+US,NEWTON,KS,38.0076,-97.2953,23.215.15.9
+CA,MONTROYAL,QC,45.52,-73.65,72.246.43.232
+DK,AALBORG,"",57.05,9.93,213.155.156.206
+AT,SCHWARZACH,"",47.45,9.75,2.16.217.206
+PL,GORZOW,"",51.03,18.43,80.239.222.169
+US,OFALLON,MO,38.8357,-90.7206,96.17.14.16
+US,KENT,WA,47.3814,-122.2339,184.84.180.101
+US,WANTAGH,NY,40.6810,-73.5104,184.26.44.38
+US,UNIONTOWN,PA,39.8676,-79.7351,184.28.17.76
+US,BROKENBOW,OK,34.0533,-94.7758,23.215.15.32
+US,RAMSEY,NJ,41.0594,-74.1457,184.51.125.68
+US,FRAZIERPARK,CA,34.9441,-119.1553,184.50.26.201
+US,YPSILANTI,MI,42.1967,-83.6251,23.63.227.227
+MP,SAIPAN,"",16.0000,145.5003,63.243.241.248
+US,MACCLENNY,FL,30.2647,-82.1181,23.79.240.37
+ID,TIME,"",0.15,101.25,23.15.10.106
+BG,VARNA,"",43.22,27.92,23.62.237.133
+US,OILCITY,PA,41.4798,-79.6741,165.254.144.25
+DK,EJBY,"",55.43,9.95,213.155.156.207
+US,HUDSON,OH,41.2467,-81.4522,63.216.54.236
+AL,TIRANA,"",41.33,19.82,85.205.31.88
+US,ANNISTON,AL,33.6763,-85.9351,72.246.65.37
+IT,ANCONA,"",43.63,13.50,193.45.15.198
+US,CABERY,IL,40.9777,-88.1923,65.113.249.11
+CH,REINACH,"",47.27,8.18,23.14.94.224
+US,NEWTOWN,PA,40.2672,-74.9516,184.26.44.38
+US,CRESCENTCITY,CA,41.7011,-123.7874,184.27.179.181
+US,COUNTRYCLUBHILLS,IL,41.5589,-87.7259,23.67.60.223
+US,NASHUA,NH,42.7370,-71.4488,23.67.244.248
+US,CAMDEN,NJ,39.9258,-75.12,23.67.242.156
+US,SHARPSBURG,GA,33.3810,-84.6468,23.79.240.36
+JP,OITA,44,33.24,131.61,23.15.1.67
+CN,JINHUA,ZJ,29.12,119.65,72.246.191.19
+US,SPRINGVALLEY,CA,32.7449,-116.9981,23.216.10.78
+US,LAVERNE,CA,34.1693,-117.7375,107.14.44.185
+US,PACIFIC,WA,47.2721,-122.2428,23.212.59.63
+DZ,OUARGLA,"",31.96,5.33,79.140.94.254
+AU,LOWERPLENTY,VIC,-37.73,145.12,184.84.221.116
+CO,PEREIRA,"",4.82,-75.70,23.74.2.12
+CA,CORNWALL,ON,45.02,-74.73,67.69.197.95
+DE,WEINBACH,HE,50.43,8.30,195.145.147.101
+US,LAKEVILLA,IL,42.4132,-88.0615,23.67.60.217
+US,AVONDALE,AZ,33.4440,-112.3152,184.50.26.179
+TC,GRANDTURK,"",21.47,-71.13,23.74.2.7
+NO,HALDEN,"",59.15,11.38,2.21.240.61
+IN,ERNAKULAM,KL,9.98,76.28,2.21.240.40
+CA,MOOSEJAW,SK,50.40,-105.55,184.150.187.229
+DZ,ALGER,"",36.76,3.05,79.140.94.254
+US,HARTWELL,GA,34.3416,-82.926,23.79.240.36
+RU,ASTRAKHAN,"",57.82,51.26,2.21.240.40
+US,GLENNVILLE,GA,31.9485,-81.9795,63.216.54.231
+AU,ARTARMON,NSW,-33.82,151.18,23.62.8.21
+US,MISSIONHILLS,CA,34.2663,-118.4599,184.50.26.179
+US,WAYNESBORO,VA,38.0936,-78.8951,184.26.44.40
+US,NOVATO,CA,38.1262,-122.559,23.61.195.165
+US,MARSHALL,MO,39.0733,-93.1988,23.215.15.9
+US,ALTOONA,PA,40.5542,-78.4349,184.28.17.55
+DE,ESSEN,NW,51.45,7.02,80.157.170.154
+US,LOMBARD,IL,41.8742,-88.0172,23.67.60.220
+GB,GLOUCESTER,EN,51.83,-2.25,95.101.2.122
+US,NATICK,MA,42.2868,-71.3531,23.67.242.139
+US,ENGLISHTOWN,NJ,40.2769,-74.3692,184.26.44.38
+US,FRESHMEADOWS,NY,40.7391,-73.7931,184.26.44.42
+CA,BARRIE,ON,44.38,-79.70,209.148.192.61
+PT,PORTO,"",41.15,-8.62,212.113.165.106
+US,BRIDGEWATER,NJ,40.5945,-74.6244,184.26.44.38
+US,ALVIN,TX,29.4018,-95.2649,23.212.53.64
+US,INOLA,OK,36.1597,-95.5177,23.74.8.8
+US,JUPITER,FL,26.9429,-80.1337,184.25.157.155
+CO,MEDELLIN,"",6.25,-75.58,23.74.2.12
+US,TRAVERSECITY,MI,44.7515,-85.6942,23.63.227.214
+US,LIBBY,MT,48.3326,-115.3444,184.27.179.179
+BO,SANTACRUZDELASIERRA,"",-17.80,-63.17,200.91.22.125
+US,SOMERSET,KY,37.0813,-84.4741,107.14.38.227
+AU,FRANKSTON,VIC,-38.13,145.12,165.254.45.32
+US,ROCKINGHAM,NC,34.9229,-79.8048,209.18.41.23
+US,SALISBURY,MD,38.3511,-75.5976,23.192.161.16
+US,SCARSDALE,NY,40.9890,-73.793,184.51.125.79
+US,BELAIR,MD,39.5372,-76.3514,23.192.161.16
+US,RIORANCHO,NM,35.2441,-106.7528,63.226.34.173
+UA,POLTAVA,"",49.58,34.57,92.122.215.67
+IR,FARS,"",35.18,59.38,96.17.182.130
+US,PANAMACITYBEACH,FL,30.2113,-85.7957,23.79.240.48
+CZ,OSTRAVA,"",49.83,18.28,23.62.237.138
+US,ABBEVILLE,SC,34.1653,-82.3751,204.2.243.143
+US,GAS,KS,37.9244,-95.3395,23.77.234.11
+US,GULFPORT,MS,30.3896,-89.0988,23.212.53.75
+DE,DUISBURG,NW,51.43,6.75,80.157.170.221
+US,LEAKESVILLE,MS,31.1153,-88.5168,184.51.35.226
+UA,KYYIV,"",50.43,30.52,92.122.215.89
+AU,BLACKTOWN,NSW,-33.77,150.92,23.62.8.25
+PH,CEBU,"",10.31,123.89,202.78.83.175
+US,BARTLESVILLE,OK,36.7524,-96.0733,63.235.21.140
+US,WOBURN,MA,42.4867,-71.1543,184.25.109.196
+ID,CIREBON,"",-6.73,108.57,118.98.37.103
+US,COCOA,FL,28.3696,-80.7478,184.51.145.7
+US,CASAGRANDE,AZ,32.8794,-111.7568,184.50.26.201
+US,MARKSVILLE,LA,31.1750,-91.9985,96.17.153.162
+RU,DELTA,"",46.64,48.05,2.22.52.105
+IN,PATNA,KA,12.77,74.87,96.17.182.136
+US,HELENA,MT,46.5543,-112.1629,165.254.1.206
+US,MCALLEN,TX,26.2183,-98.2399,184.26.93.111
+CA,ESTEVAN,SK,49.15,-103.00,184.150.187.229
+IT,PESCARA,"",42.75,13.27,95.101.34.105
+SE,LULEA,BD,65.58,22.15,82.96.58.102
+RU,SEVEROKURILSK,"",50.68,156.12,96.7.251.97
+JP,OKAYAMA,33,34.65,133.92,202.229.2.213
+US,PALATKA,FL,29.7389,-81.6715,23.79.240.36
+US,WESTCHICAGO,IL,41.9000,-88.2142,107.14.38.217
+RO,RESITA,"",45.30,21.90,81.196.26.237
+US,CROSSVILLE,TN,35.9347,-85.0211,23.215.15.9
+US,YORBALINDA,CA,33.8876,-117.8023,184.87.195.109
+US,SYKESVILLE,MD,39.3995,-76.9748,23.192.161.21
+US,HANA,HI,20.7422,-156.1196,23.216.10.78
+US,NEWPALTZ,NY,41.7512,-74.0601,24.143.199.156
+GB,POOLE,EN,50.72,-2.00,23.67.255.106
+RO,IASI,"",45.77,24.93,81.196.26.231
+US,SOUTHHOLLAND,IL,41.5964,-87.6014,107.14.38.217
+US,WARRENTON,VA,38.6876,-77.819,184.26.44.42
+US,GILMER,TX,32.7226,-94.9896,23.212.53.64
+US,CHOCTAW,OK,35.4577,-97.2616,23.74.8.8
+IN,MANGALORE,KA,12.86,74.84,23.57.76.20
+US,WALLINGTON,NJ,40.8534,-74.1065,23.67.242.139
+AT,WEISSACH,"",47.47,12.52,195.145.147.101
+US,MABLETON,GA,33.8161,-84.553,23.212.53.64
+CR,HEREDIA,"",10.00,-84.12,23.215.15.22
+US,OTTUMWA,IA,41.0803,-92.3054,65.113.249.8
+US,VERMILION,OH,41.3884,-82.3643,107.14.38.217
+HU,GYOR,"",47.68,17.63,23.14.94.220
+IN,PATEL,JK,32.98,74.86,23.57.69.157
+JE,SAINTHELIER,"",49.18,-2.10,195.59.54.141
+AU,ASHFIELD,NSW,-33.88,151.12,165.254.45.13
+US,FORESTHILLS,NY,40.7228,-73.845,24.143.199.188
+SA,LINE,"",28.76,43.74,79.140.94.243
+IN,LUCKNOW,UP,26.85,80.92,23.57.69.156
+US,SUNBURY,OH,40.2799,-82.849,107.14.38.217
+CA,LABAIE,QC,48.33,-70.87,67.69.197.92
+US,SARANACLAKE,NY,44.3202,-74.2149,107.14.38.227
+KZ,TALDYKORGAN,"",45.02,78.37,23.14.94.224
+US,CATONSVILLE,MD,39.2711,-76.7461,23.192.161.21
+US,DAMASCUS,MD,39.2916,-77.2137,184.27.45.150
+AR,SANMIGUEL,"",-34.52,-58.78,200.123.201.219
+JP,YAMAGATA,06,38.25,140.34,202.229.2.212
+US,NORTHPORT,FL,27.0874,-82.2022,192.204.11.226
+RU,SARATOV,"",51.57,46.03,2.21.240.61
+GH,ACCRA,"",5.55,-0.22,23.212.108.28
+US,FAIRBURN,GA,33.5864,-84.6255,23.79.240.37
+CZ,BRNO,"",49.20,16.63,23.62.237.135
+US,ELSOBRANTE,CA,37.9619,-122.283,96.17.12.48
+US,STEPHENVILLE,TX,32.2465,-98.2492,23.215.15.22
+US,SYCAMORE,IL,42.0146,-88.6891,23.67.60.223
+US,WOODLANDHILLS,CA,34.1552,-118.5942,184.50.26.179
+BR,CANOAS,MG,-21.42,-46.97,187.59.4.154
+IL,PETACHTIKVAH,"",32.09,34.87,212.25.69.142
+US,MURRELLSINLET,SC,33.5501,-79.0592,69.31.132.226
+US,COLONIALHEIGHTS,VA,37.2887,-77.3954,184.28.17.76
+US,HOPKINS,MN,44.9540,-93.4312,165.254.96.242
+GB,WALTON,EN,51.38,-0.43,23.67.255.158
+US,DEXTER,MO,36.7491,-89.9236,184.28.17.55
+US,MARICOPA,AZ,33.0567,-112.0467,63.226.34.176
+US,WESTHILLS,CA,34.2068,-118.6798,184.50.26.179
+US,HILLSDALE,MI,41.8825,-84.6162,23.67.60.223
+CZ,LIBEREC,"",50.76,15.07,92.122.189.85
+BR,NATAL,RN,-5.78,-35.22,190.98.142.115
+PK,WAN,"",32.42,71.69,23.75.23.140
+RO,CRAIOVA,"",44.32,23.80,81.196.26.231
+US,HARTVILLE,OH,40.9665,-81.3038,107.14.38.217
+US,BEAVER,WV,37.7672,-81.0206,184.28.17.76
+US,BOLINGBROOK,IL,41.6956,-88.0759,23.67.60.223
+US,LYNBROOK,NY,40.6573,-73.674,23.67.242.139
+HU,DUNAUJVAROS,"",46.98,18.93,23.14.94.220
+TR,INCESU,"",39.92,32.88,193.45.15.198
+CA,SELKIRK,MB,50.15,-96.88,23.74.8.8
+US,HOWE,IN,41.7293,-85.4292,205.185.195.170
+US,CHERRYHILL,NJ,39.9312,-75.0244,23.67.242.139
+JP,TSUKUBA,08,36.08,140.12,23.15.1.55
+US,ALLENDALE,MI,42.9767,-85.9382,165.254.207.111
+SE,NORRKOPING,E,58.60,16.18,213.155.156.207
+US,OMAK,WA,48.4274,-119.5241,184.27.179.159
+US,ESCALON,CA,37.8207,-121.0167,96.17.12.48
+US,RIDGEWOOD,NY,40.7008,-73.8892,24.143.199.156
+US,RESEDA,CA,34.2011,-118.5406,184.50.26.204
+ID,BANJARMASIN,"",-4.75,104.55,23.0.162.54
+US,SEABROOK,TX,29.5802,-95.0274,23.212.53.75
+BR,PALMAS,TO,-10.42,-48.44,189.72.175.118
+US,CANONCITY,CO,38.5330,-105.3899,107.14.32.235
+US,CALDWELL,TX,30.5405,-96.7258,23.215.15.22
+FR,REST,"",47.92,-4.20,77.67.27.250
+MX,CAMPECHE,CAM,19.85,-90.53,23.212.53.75
+US,NORRISTOWN,PA,40.1271,-75.3202,184.26.44.38
+JP,GIFU,21,35.42,136.75,117.104.139.136
+US,KERNERSVILLE,NC,36.1188,-80.075,209.18.41.23
+US,POUGHKEEPSIE,NY,41.7144,-73.9069,184.26.44.42
+US,EULESS,TX,32.8604,-97.0691,213.155.156.206
+US,FOUNTAINHILLS,AZ,33.5988,-111.7413,184.50.26.204
+US,REIDSVILLE,NC,36.3355,-79.6561,209.18.41.27
+PL,BYDGOSZCZ,"",53.15,18.00,2.22.52.101
+US,WAXAHACHIE,TX,32.3150,-96.7926,96.16.7.101
+US,WIGGINS,MS,30.8678,-89.1157,96.17.153.162
+RE,LEPORT,"",-20.92,55.30,81.52.201.77
+US,DERRY,NH,42.8895,-71.2818,184.25.109.200
+BO,COCHABAMBA,"",-17.38,-66.15,72.246.65.26
+PL,KOSZALIN,"",54.20,16.18,2.22.52.101
+US,MUKWONAGO,WI,42.8738,-88.3526,107.14.38.218
+DE,SCHWERIN,MV,53.63,11.38,80.157.170.221
+LA,VIENTIANE,"",17.97,102.60,23.61.195.149
+JP,OMIHACHIMAN,25,35.14,136.08,202.229.2.227
+US,AUBURNDALE,FL,28.0903,-81.8298,23.33.186.101
+CA,VERDUN,QC,45.45,-73.57,204.93.33.141
+HU,KISVARDA,"",48.22,22.08,80.239.222.167
+LY,TRIPOLI,"",32.89,13.18,79.140.94.234
+US,BELLFLOWER,CA,33.8879,-118.1274,23.216.10.54
+US,REISTERSTOWN,MD,39.4886,-76.8057,23.192.161.21
+US,KEYWEST,FL,24.5796,-81.6849,23.79.240.48
+ID,TIMUR,"",-8.18,131.08,96.17.180.166
+US,MUNFORDVILLE,KY,37.3145,-85.9322,23.220.100.223
+US,WATERVLIET,NY,42.7341,-73.7188,23.215.15.9
+US,PARKCITY,UT,40.6558,-111.5034,23.61.195.165
+US,PORTALES,NM,34.1669,-103.2665,96.17.177.63
+US,COLLEGEVILLE,PA,40.1903,-75.4384,184.26.44.38
+US,SOUTHLAKETAHOE,CA,38.8829,-120.0344,23.216.10.54
+VE,MERIDA,"",8.60,-71.14,23.74.2.7
+US,LADERARANCH,CA,33.5682,-117.6365,184.50.26.194
+US,GAFFNEY,SC,35.0161,-81.6141,23.79.240.36
+US,LAMARQUE,TX,29.3673,-94.9891,23.212.53.75
+VG,ROADTOWN,"",18.42,-64.62,23.33.186.134
+RU,ARKHANGELSK,"",55.48,36.40,2.21.240.61
+ZM,LUSAKA,"",-15.42,28.28,41.193.163.53
+US,CYPRESS,TX,29.9695,-95.6976,96.17.163.165
+US,PURCELLVILLE,VA,39.1720,-77.7306,184.27.45.150
+US,PITTSFIELD,MA,42.4608,-73.282,107.14.38.218
+HU,SZOLNOK,"",47.18,20.20,23.62.237.135
+US,BRODHEADSVILLE,PA,40.9370,-75.4125,184.26.44.40
+IN,KALYAN,MH,19.25,73.15,23.211.135.66
+DK,BALLERUP,"",55.73,12.37,23.65.29.106
+US,ARVADA,CO,39.8028,-105.0869,63.235.21.147
+US,SAINTCLAIRSHORES,MI,42.4633,-82.9002,23.67.60.220
+KR,ILSAN,"",38.18,127.82,125.56.214.147
+US,LOGANSPORT,IN,40.8028,-86.3678,23.67.60.222
+US,CHARLEVOIX,MI,45.2393,-85.3038,23.63.227.214
+ID,BANDUNG,"",-6.90,107.60,23.0.162.54
+US,LOGANVILLE,GA,33.8218,-83.8917,72.246.65.23
+US,MACUNGIE,PA,40.5204,-75.5692,184.26.44.38
+US,SANDSPRINGS,OK,36.1933,-96.1589,165.254.137.75
+US,BALDWIN,NY,40.6539,-73.609,23.67.242.139
+US,SANDIMAS,CA,34.1088,-117.8082,23.216.10.78
+NZ,PAPATOETOE,"",-36.98,174.85,219.88.186.164
+FI,OULU,"",65.02,25.47,2.21.240.40
+DE,HERZOGENAURACH,BY,49.55,10.88,84.53.146.39
+CN,CHANGZHOU,JS,31.78,119.97,184.50.87.178
+US,JERSEYSHORE,PA,41.4260,-77.4189,23.192.161.21
+US,GROVES,TX,29.9495,-93.9207,107.14.36.199
+CA,YORKTON,SK,51.22,-102.47,184.150.187.229
+US,SARATOGASPRINGS,NY,43.0842,-73.7411,209.18.41.23
+US,BUFFALOGROVE,IL,42.1650,-87.9695,107.14.38.218
+BR,FOZDOIGUACU,PR,-25.55,-54.58,187.59.4.147
+US,KILMARNOCK,VA,37.7427,-76.3858,208.185.55.117
+US,CUSTER,SD,43.6653,-103.7669,23.63.227.227
+US,KEWANEE,IL,41.2504,-89.9568,23.67.60.220
+RO,SLATINA,"",44.43,24.37,81.196.26.236
+US,ELIZABETHTOWN,KY,37.7021,-85.8419,23.220.100.223
+US,ROBERT,LA,30.5167,-90.3282,96.17.153.157
+US,CALEXICO,CA,32.6882,-115.5488,23.215.15.9
+JP,MITO,08,36.37,140.47,72.246.191.19
+DE,WIESBADEN,HE,50.08,8.25,23.14.94.228
+US,ORION,IL,41.3669,-90.3966,23.74.8.8
+NO,GREAKER,"",59.27,11.03,213.155.156.212
+CR,SANPEDRO,"",9.93,-84.05,72.164.253.83
+US,CASTROVILLE,TX,29.3805,-98.9015,107.14.43.29
+US,ABINGDON,VA,36.7393,-82.0092,23.67.60.222
+US,MILLBURN,NJ,40.7229,-74.3006,23.67.242.156
+CA,QUEBEC,QC,46.80,-71.25,67.69.197.95
+US,PALOSHILLS,IL,41.7012,-87.8574,23.67.60.217
+US,GLENROSE,TX,32.2052,-97.8091,205.185.195.170
+US,CHENEY,WA,47.4110,-117.6288,206.104.149.133
+US,FRISCO,TX,33.1507,-96.8235,184.28.23.4
+US,ARTESIA,CA,33.8679,-118.081,23.216.10.78
+US,ROCKLEDGE,FL,28.2781,-80.7792,23.34.56.147
+US,SCRANTON,PA,41.4088,-75.6626,23.192.161.21
+BR,CASCAVEL,PR,-24.95,-53.47,187.59.4.154
+US,NEWIBERIA,LA,29.9366,-91.8695,96.17.153.157
+US,ARMONK,NY,41.1347,-73.7005,23.67.242.139
+US,FORTMILL,SC,35.0493,-80.9623,184.51.35.226
+US,READING,PA,40.3659,-75.9566,23.192.161.16
+US,MATTOON,IL,39.5101,-88.3823,205.185.195.170
+RU,VOLGA,"",57.95,38.40,213.200.109.183
+NO,DRAMMEN,"",59.74,10.21,213.155.156.212
+US,ELSEGUNDO,CA,33.9182,-118.4042,184.50.26.179
+US,EGYPT,TX,29.4044,-96.2367,23.212.53.64
+IR,KARAJ,"",35.72,51.11,96.17.182.136
+NZ,PALMERSTONNORTH,"",-40.35,175.62,219.88.186.167
+ID,MAGELANG,"",-7.47,110.22,23.0.162.46
+US,EAGLEMOUNTAIN,UT,40.3099,-111.9316,184.50.26.179
+US,BULVERDE,TX,29.7881,-98.4616,184.26.93.116
+CH,SANKTGALLEN,"",47.47,9.40,193.247.167.214
+IN,RAJKOT,GJ,22.30,70.78,23.211.135.66
+US,SAVAGE,MN,44.7628,-93.362,204.93.47.216
+US,ALTADENA,CA,34.1951,-118.14,63.217.232.17
+RO,BACAU,"",46.57,26.90,81.196.26.231
+DE,MAUER,BW,49.34,8.80,195.95.193.147
+PL,LECZNA,"",52.42,20.72,2.22.52.109
+CZ,TEPLICE,"",50.63,13.83,23.74.24.66
+US,HILLAFB,UT,41.1284,-111.9912,184.84.180.98
+US,SPRINGTOWN,TX,32.9715,-97.6513,23.212.53.64
+US,ROSELLE,NJ,40.6527,-74.2601,184.26.44.38
+SE,LYCKSELE,AC,64.60,18.67,2.21.240.61
+VN,QUANGTRUNG,"",20.70,105.37,23.76.205.111
+US,CERRITOS,CA,33.8673,-118.0676,184.50.26.194
+US,BETHLEHEM,PA,40.5862,-75.372,184.27.45.150
+US,PRICE,UT,39.5589,-110.9112,23.215.15.9
+US,OAKRIDGE,NC,36.1724,-79.9835,209.18.41.27
+FR,BELFORT,"",47.63,6.87,2.16.117.200
+US,LEHIGHACRES,FL,26.5583,-81.6174,23.212.53.75
+US,HESPERIA,CA,34.4264,-117.3001,23.216.10.54
+US,PENNSVILLE,NJ,39.6375,-75.5059,23.192.161.30
+IT,RIPESANGINESIO,"",43.15,13.37,95.101.34.109
+FR,LESMINIMES,"",43.62,1.43,2.16.117.185
+US,LAPUENTE,CA,34.0289,-117.9371,23.216.10.78
+MY,SABAH,"",3.77,100.98,203.106.85.4
+US,SUNVALLEY,CA,34.2294,-118.357,63.233.112.196
+US,PLAYADELREY,CA,33.9505,-118.4382,23.216.10.54
+CA,DUNCAN,BC,48.78,-123.70,184.27.179.159
+US,MAPLEHEIGHTS,OH,41.4092,-81.5624,96.17.9.14
+GB,GUILDFORD,EN,51.22,-0.57,88.221.87.94
+TH,PAKKRED,"",13.92,100.50,110.164.11.181
+US,ELCAMPO,TX,29.1916,-96.2212,184.28.23.24
+US,ROWLETT,TX,32.9026,-96.5636,23.5.164.143
+US,WOODVILLE,TX,30.7643,-94.4448,65.116.149.89
+US,OLIVEHURST,CA,39.0904,-121.5521,23.212.52.79
+CA,LENNOXVILLE,QC,45.37,-71.87,72.246.43.215
+US,WINFIELD,WV,38.5058,-81.9328,184.27.45.150
+US,MAHWAH,NJ,41.0818,-74.1862,165.254.35.182
+US,RAMONA,CA,33.0538,-116.8517,173.223.52.67
+US,REHOBOTH,MA,41.8440,-71.246,184.25.109.200
+US,MANISTIQUE,MI,46.1571,-86.3397,184.85.215.170
+US,LARGO,FL,27.9154,-82.8023,192.204.82.239
+ES,BASAURI,"",43.02,-2.40,92.122.188.161
+US,WALLAWALLA,WA,46.1270,-118.3596,184.27.179.187
+US,SCOTTSVILLE,KY,36.7794,-86.196,63.216.54.236
+US,MANASSAS,VA,38.7657,-77.4852,23.192.161.16
+IN,GOLD,JK,33.59,74.14,96.17.182.130
+US,SANMARINO,CA,34.1223,-118.1135,23.215.15.9
+SE,SOLNA,AB,59.37,18.02,2.21.240.40
+BG,PERNIK,"",42.60,23.03,2.20.45.104
+JP,HIROSHIMA,34,34.40,132.45,23.3.74.113
+GB,EDINBURGH,SC,55.95,-3.20,88.221.87.94
+MX,NUEVOLAREDO,TAM,27.50,-99.52,23.5.164.146
+US,GLENWOOD,IA,41.0322,-95.6979,23.77.234.11
+US,THECOLONY,TX,33.0886,-96.9013,184.28.23.24
+HU,GODOLLO,"",47.60,19.37,23.14.94.220
+US,LLANO,TX,30.6126,-98.6923,23.215.15.9
+US,NEWALBANY,IN,38.2909,-85.8472,23.220.100.224
+US,THOUSANDOAKS,CA,34.1707,-118.8364,184.50.26.179
+US,DECATUR,IL,39.8055,-88.9128,23.67.60.220
+CR,ALAJUELA,"",10.02,-84.22,23.74.2.12
+US,HOLLAND,MI,42.7878,-86.1086,23.63.227.223
+BS,NASSAU,"",25.08,-77.35,72.164.253.83
+SE,VASTERAS,U,59.62,16.55,2.21.240.61
+RO,SLOBOZIA,"",44.38,25.93,72.246.43.237
+US,BARTONSVILLE,PA,41.0176,-75.2939,204.94.155.231
+GB,BRADFORD,EN,53.78,-1.75,88.221.87.94
+US,WHITESBURG,KY,37.1283,-82.8498,63.151.29.12
+US,STEVENSPOINT,WI,44.5531,-89.5186,65.113.249.11
+US,MILLBRAE,CA,37.5972,-122.4192,96.17.12.44
+VU,PORTVILA,"",-17.73,168.32,23.62.8.25
+US,ROCKWELL,NC,35.5293,-80.4409,209.18.41.27
+US,JEMISON,AL,32.9898,-86.6799,184.51.35.215
+US,EDENPRAIRIE,MN,44.8655,-93.4304,23.215.15.22
+NO,MANGER,"",60.77,5.35,213.155.156.212
+US,MCCALLA,AL,33.3452,-87.0035,23.220.100.224
+CG,BRAZZAVILLE,"",-4.26,15.28,95.101.34.109
+US,EDINBORO,PA,41.8735,-80.1661,184.26.44.38
+US,WOODDALE,IL,41.9645,-87.9808,23.67.60.220
+US,ENCINITAS,CA,33.0368,-117.2914,63.235.21.147
+US,ERLANGER,KY,39.0170,-84.607,184.51.147.33
+US,LYNCHBURG,VA,37.3527,-79.1576,184.27.45.157
+US,LULING,TX,29.6952,-97.6509,107.14.36.199
+US,PRATTVILLE,AL,32.4989,-86.4129,64.86.201.121
+US,CULLMAN,AL,34.1748,-86.8225,23.5.164.143
+US,WHITEPLAINS,NY,41.0328,-73.7651,184.51.125.79
+US,WILDWOOD,NJ,38.9808,-74.8281,184.26.44.38
+EE,PARNU,"",58.37,24.51,2.21.240.40
+US,PRAIRIEDUSAC,WI,43.3094,-89.8029,184.85.215.170
+US,CHARLTONHEIGHTS,WV,38.1238,-81.2342,184.28.17.76
+US,GREENVALLEY,AZ,31.8307,-111.0345,63.226.34.174
+US,EATONTOWN,NJ,40.2996,-74.074,23.212.53.64
+US,HYANNIS,MA,41.6607,-70.2924,184.25.109.196
+US,BRAWLEY,CA,32.9870,-115.4637,63.235.21.141
+TR,SABANCI,"",37.48,39.35,2.20.142.166
+US,BROWNWOOD,TX,31.6193,-98.9922,23.215.15.22
+AT,MICHELDORF,"",47.87,14.13,46.33.70.104
+US,DAHLONEGA,GA,34.5608,-84.0088,63.216.54.216
+DE,MANHEIM,NW,50.88,6.60,23.14.94.224
+US,ESTHERVILLE,IA,43.3937,-94.7541,65.113.249.8
+TW,SHOUFENG,"",23.87,121.50,61.220.62.171
+US,LOCKHART,TX,29.8965,-97.6713,107.14.36.199
+US,RADFORD,VA,37.1746,-80.6425,96.6.47.106
+IN,SIKKA,GJ,22.43,69.83,23.57.69.157
+KZ,PETROPAVLOVSK,"",54.88,69.16,23.14.94.228
+US,KAYSVILLE,UT,41.0365,-111.927,23.61.195.166
+US,PONTIAC,MI,42.6705,-83.292,23.67.60.222
+US,FRAMINGHAM,MA,42.3203,-71.4404,184.29.107.20
+CA,AJAX,ON,43.85,-79.02,72.246.43.215
+US,HAYDEN,ID,47.7955,-116.5418,184.27.179.181
+US,VALLEJO,CA,38.1438,-122.2502,23.61.195.165
+FR,CROIX,"",49.80,2.98,95.100.171.16
+US,DELRIO,TX,29.8301,-100.8984,107.14.36.199
+KH,PREAH,"",13.60,105.07,23.76.205.111
+RU,KEMEROVO,"",55.33,86.08,2.21.240.61
+VN,DONGNAI,"",18.10,106.33,23.5.165.167
+MG,ANTANANARIVO,"",-18.92,47.52,81.52.201.98
+US,ETTERS,PA,40.1451,-76.7914,23.192.161.16
+US,MATHIS,TX,28.0654,-97.7489,184.26.93.111
+US,VALDESE,NC,35.7374,-81.5644,184.27.45.157
+GB,MIDDLESBROUGH,EN,54.57,-1.16,88.221.87.94
+RU,VLADIMIR,"",56.14,40.40,217.212.227.25
+FR,SUCYENBRIE,"",48.77,2.53,2.16.117.190
+US,RIDGEFIELDPARK,NJ,40.8547,-74.0203,23.67.242.139
+US,SURPRISE,AZ,33.6321,-112.3824,184.50.26.185
+US,BROOKFIELD,WI,43.0627,-88.099,107.14.38.227
+AU,SAINTLUCIA,QLD,-27.50,153.00,23.62.157.31
+US,MOUNTSTERLING,KY,38.0657,-83.9424,23.61.195.163
+US,BURNSVILLE,MN,44.7310,-93.293,23.67.60.222
+BA,ZENICA,"",43.89,18.31,23.14.94.220
+US,FLOURTOWN,PA,40.1083,-75.2168,184.27.45.157
+CA,PETERBOROUGH,ON,44.30,-78.33,72.246.43.237
+RU,BELGOROD,"",52.87,34.65,2.21.240.40
+US,LUTHERVILLETIMONIUM,MD,39.4394,-76.6555,23.192.161.21
+US,PORTMURRAY,NJ,40.7953,-74.9091,23.192.161.16
+ID,JEMBER,"",-8.17,113.70,23.0.162.54
+US,LIBERTY,NY,41.7928,-74.7401,184.26.44.42
+US,CUSHING,OK,35.9968,-96.7376,184.28.23.24
+AT,ENNSDORF,"",48.20,14.48,46.33.70.97
+GR,KOMOTINI,"",41.12,25.40,80.157.169.18
+US,ESSEXJUNCTION,VT,44.5358,-73.0548,184.25.109.200
+US,OCALA,FL,29.2239,-82.088,184.51.35.226
+US,ALMA,MI,43.3819,-84.6786,23.63.227.227
+US,PORTLAVACA,TX,28.5342,-96.663,23.215.15.9
+HU,GOD,"",47.70,19.13,23.14.94.220
+US,NORTHHIGHLANDS,CA,38.6687,-121.3891,96.17.12.48
+US,TUNKHANNOCK,PA,41.5722,-75.9275,184.26.44.42
+US,ALLISONPARK,PA,40.5779,-79.9517,184.27.45.157
+US,MONROEVILLE,PA,40.4264,-79.7596,96.6.47.120
+US,PEWAUKEE,WI,43.0807,-88.2675,107.14.38.218
+US,STREAMWOOD,IL,42.0230,-88.1742,23.67.60.220
+US,BATH,NY,42.3460,-77.3478,107.14.38.218
+JP,KOKURYO,13,35.65,139.57,96.7.251.95
+TR,BAHCELIEVLER,"",39.93,32.83,46.33.70.213
+RU,RYAZAN,"",55.67,36.67,213.155.156.212
+US,HORNITOS,CA,37.4864,-120.2361,165.254.144.32
+US,CHANNAHON,IL,41.4089,-88.1749,96.17.14.16
+US,PHILLIPSBURG,NJ,40.7083,-75.1472,23.67.242.139
+US,WINONA,MN,43.9823,-91.6349,184.51.147.6
+US,BASTROP,LA,32.8721,-91.912,23.5.164.143
+US,LEESBURG,FL,28.8097,-81.8939,184.25.157.169
+US,HANFORD,CA,36.2869,-119.6218,23.212.52.88
+DE,LEVERKUSEN,NW,51.03,7.00,92.122.215.67
+IN,ERODE,TN,11.35,77.73,117.239.240.96
+US,NAPOLEON,OH,41.4176,-84.1859,107.14.38.218
+US,KINGMAN,AZ,35.4636,-113.9441,184.85.249.14
+RO,TARGUJIU,"",45.05,23.28,81.196.26.236
+DE,FULDA,HE,50.55,9.67,80.157.150.197
+AU,PORTMELBOURNE,VIC,-37.83,144.93,150.101.152.249
+US,SALINA,KS,38.8424,-97.6193,23.77.234.35
+CH,OERLIKON,"",47.42,8.55,194.25.95.214
+US,FLAGSTAFF,AZ,35.4784,-111.738,24.143.194.216
+ES,MALAGA,"",36.72,-4.42,2.16.1.106
+US,COLLEGEPARK,MD,38.9974,-76.9284,184.27.45.150
+CN,WUXI,JS,31.58,120.29,117.103.188.218
+US,BOYNTONBEACH,FL,26.5253,-80.0668,184.28.184.6
+US,NORTHRICHLANDHILLS,TX,32.8656,-97.2164,23.215.15.22
+US,BLACKWOOD,NJ,39.7780,-75.0552,184.26.44.38
+US,MCHENRY,IL,42.3590,-88.2783,184.27.120.50
+US,DEERPARK,TX,29.7032,-95.1146,23.212.53.75
+US,MARRERO,LA,29.8286,-90.1189,96.17.153.157
+US,LOVINGTON,NM,32.9094,-103.4796,198.172.88.205
+CA,ORANGEVILLE,ON,43.92,-80.08,72.246.43.215
+CN,DONGYING,SD,37.46,118.49,173.223.52.67
+RO,BUZAU,"",45.15,26.83,88.221.93.157
+PK,ISAN,"",31.46,74.01,96.17.182.130
+ES,ALICANTE,"",38.35,-0.48,92.123.73.26
+US,MAYSLANDING,NJ,39.4502,-74.7366,184.26.44.38
+US,LENOIRCITY,TN,35.8295,-84.286,23.79.240.48
+US,AMERY,WI,45.3559,-92.3527,23.63.227.214
+US,SPENCER,MA,42.2477,-71.9927,63.141.200.241
+RU,KAMENSK,"",52.99,32.47,92.122.189.85
+US,GWYNNOAK,MD,39.3248,-76.7203,23.192.161.16
+US,WESTLEBANON,NH,43.6438,-72.295,23.192.161.21
+US,MAGNOLIA,AR,33.2253,-93.2572,23.5.164.143
+IN,MANIPALA,KA,13.35,74.78,23.57.69.159
+US,OSCEOLA,AR,35.6763,-90.0131,173.197.194.159
+US,LORTON,VA,38.6817,-77.2042,23.220.148.108
+US,SANTEE,CA,32.8510,-117.008,184.50.26.204
+US,KINGSTREE,SC,33.7042,-79.7562,209.18.41.23
+US,KERRVILLE,TX,30.0272,-99.1089,184.26.93.116
+US,BAINBRIDGE,GA,30.9045,-84.5727,184.28.127.55
+US,HALFMOONBAY,CA,37.4511,-122.4142,184.85.249.6
+FR,WOERTH,"",48.38,7.63,2.16.117.190
+US,SPANAWAY,WA,47.0761,-122.3963,23.212.59.63
+BR,FLORIANOPOLIS,SC,-27.58,-48.57,187.59.4.154
+ZA,BELLVILLE,"",-33.90,18.63,165.165.46.37
+US,WASHOUGAL,WA,45.6718,-122.2068,184.27.179.159
+US,ROUNDLAKE,IL,42.3442,-88.1158,107.14.38.224
+US,LYNCH,NE,42.8592,-98.4418,204.2.223.90
+US,LONGISLANDCITY,NY,40.7457,-73.9381,24.143.199.188
+US,RIVERVIEW,FL,27.8494,-82.3132,192.204.11.244
+US,SCHOFIELD,WI,44.9014,-89.5403,184.85.215.170
+US,ELYRIA,OH,41.3603,-82.1314,63.216.54.229
+US,GLENSFALLS,NY,43.3117,-73.645,107.14.38.217
+RU,STAR,"",53.62,34.15,80.239.237.84
+DE,WERDAU,SN,50.73,12.38,80.157.150.192
+US,ANKENY,IA,41.7301,-93.5923,23.79.255.149
+US,OWENSCROSSROADS,AL,34.6110,-86.4644,184.51.35.226
+US,ROCKYMOUNT,NC,35.9504,-77.6998,184.28.17.76
+US,HARRISON,OH,39.2734,-84.7476,184.51.147.33
+US,MINERVA,OH,40.7427,-81.0929,107.14.38.224
+US,SAYREVILLE,NJ,40.4595,-74.3616,184.51.125.68
+US,GRANBY,CO,40.0195,-105.8657,184.84.180.68
+US,OCOEE,FL,28.5761,-81.5328,23.34.56.142
+US,THIENSVILLE,WI,43.2173,-87.9347,107.14.38.218
+US,STOUGHTON,WI,42.9244,-89.2046,184.85.215.165
+US,WESTSACRAMENTO,CA,38.5921,-121.5456,23.61.195.149
+US,CALUMETCITY,IL,41.6123,-87.5504,23.67.60.222
+US,CHESWICK,PA,40.5780,-79.8433,23.192.161.21
+US,DUQUOIN,IL,38.0189,-89.2365,23.63.227.214
+PT,CORROIOS,"",38.63,-9.15,195.22.14.133
+US,CAPEGIRARDEAU,MO,37.3091,-89.5732,204.93.47.216
+US,COMBINEDLOCKS,WI,44.2639,-88.309,107.14.38.227
+US,GARDNER,MA,42.5847,-71.987,184.25.109.213
+US,DISTRICTHEIGHTS,MD,38.8541,-76.8832,184.27.45.157
+US,CORDOVA,TN,35.1578,-89.7651,23.79.240.36
+US,HERNANDO,MS,34.8026,-89.9999,23.79.240.48
+IN,BELGAUM,KA,15.87,74.50,23.57.76.18
+US,SELMA,CA,36.5405,-119.6527,23.212.52.88
+ES,SALAMANCA,"",40.97,-5.65,77.67.41.227
+RU,KHABAROVSK,"",48.50,135.10,72.246.184.81
+IN,UDAIPUR,RJ,24.58,73.68,23.205.118.109
+CA,WHITBY,ON,43.87,-78.93,72.246.43.237
+US,TARZANA,CA,34.1585,-118.5493,184.50.26.203
+US,ANDALUSIA,AL,31.2069,-86.6212,63.151.29.12
+RU,KUBAN,"",53.18,35.43,217.212.227.31
+FR,ROUBAIX,"",50.70,3.17,23.212.108.28
+GB,WOLVERHAMPTON,EN,52.58,-2.13,88.221.87.112
+JP,KAITA,31,35.45,133.85,23.3.74.113
+JP,TOYO,38,33.93,133.10,117.104.139.162
+UA,DMITRIY,"",46.65,30.40,80.239.222.167
+US,SALECREEK,TN,35.3979,-85.1221,184.51.35.226
+IN,COIMBATORE,TN,10.99,76.96,23.205.118.109
+BR,BLUMENAU,SC,-26.93,-49.05,187.59.4.154
+US,MCKEESPORT,PA,40.3339,-79.8011,23.192.161.21
+DE,FRANKEN,RP,50.50,7.23,80.157.170.221
+KZ,KUSTANAY,"",53.17,63.58,2.21.240.40
+US,ANDOVER,KS,37.7002,-97.0855,23.77.234.35
+US,TITUSVILLE,FL,28.5340,-80.8427,184.51.145.7
+US,NEWNAN,GA,33.3877,-84.8596,23.79.240.48
+UA,CHERKASY,"",49.43,32.07,23.14.94.228
+UZ,KASHKADARYA,"",38.97,65.78,23.76.205.111
+US,GOODLETTSVILLE,TN,36.3233,-86.7133,23.220.100.224
+RU,VORONEZH,"",51.67,39.17,213.155.156.208
+FR,VILLEURBANNE,"",45.77,4.88,2.16.117.190
+US,NEHALEM,OR,45.7222,-123.6842,192.80.13.117
+US,ALEXANDERCITY,AL,32.9346,-85.9597,23.79.240.48
+US,SANDPOINT,ID,48.4219,-116.5059,184.27.179.181
+AT,WINKL,"",48.38,15.90,195.145.147.101
+UA,NIKOLAEV,"",46.97,32.00,2.22.52.105
+US,SHENANDOAH,VA,38.4921,-78.5764,184.29.107.20
+US,MCLEMORESVILLE,TN,35.9867,-88.5772,69.31.132.226
+JP,YOKOSUKA,14,35.28,139.67,117.104.139.162
+US,CAPECORAL,FL,26.5778,-81.9505,23.79.240.48
+BD,TEJGAON,"",23.77,90.40,23.57.76.20
+ZW,HARARE,"",-17.86,31.03,165.165.46.36
+US,ARLINGTONHEIGHTS,IL,42.1121,-87.9793,107.14.38.218
+US,MOSESLAKE,WA,47.1758,-119.2892,206.104.149.146
+US,LONDONDERRY,NH,42.8794,-71.3877,184.25.109.200
+RU,LIPETSK,"",52.62,39.57,213.155.156.206
+US,EDWARDSVILLE,IL,38.8031,-89.9742,23.215.15.22
+US,BURNET,TX,30.8393,-98.2564,107.14.43.30
+JP,KUMAMOTO,43,32.80,130.72,117.104.139.136
+GG,SAINTPETERPORT,"",49.45,-2.53,81.25.206.208
+US,WHITEHOUSE,TX,32.2183,-95.2257,23.5.164.143
+TJ,DUSHANBE,"",38.57,68.77,2.21.240.40
+GB,WATFORD,EN,51.67,-0.40,23.67.255.158
+US,WHEATON,IL,41.8546,-88.116,23.67.60.222
+DE,TUBINGEN,BW,48.53,9.05,23.14.94.224
+NL,EINDHOVEN,"",51.45,5.47,92.122.189.114
+CD,GOMA,"",-5.32,14.40,95.101.34.105
+US,BOXBOROUGH,MA,42.4884,-71.5177,96.6.47.120
+RS,PETROVAC,"",42.42,20.43,23.62.237.137
+US,RANDOLPH,NJ,40.8481,-74.5726,184.51.125.79
+DE,WUNSIEDEL,BY,50.03,12.02,194.25.95.214
+AR,PUERTOMADRYN,"",-42.77,-65.05,72.246.216.139
+KR,INCHEON,"",37.45,126.73,61.111.58.229
+FR,NANTERRE,"",48.90,2.20,95.100.171.16
+IN,NASIK,MH,19.98,73.80,23.205.118.106
+GB,BARNSLEY,EN,53.55,-1.48,23.67.255.158
+US,ALIQUIPPA,PA,40.5921,-80.3191,184.28.17.76
+US,CONCORDIA,KS,39.4716,-97.7305,23.212.53.64
+RU,LESOSIBIRSK,"",58.29,92.39,213.155.156.207
+IN,NALGONDA,AP,17.05,79.27,23.205.118.106
+US,SHERIDAN,AR,34.3151,-92.3357,63.216.54.229
+US,EASLEY,SC,34.8763,-82.5796,23.79.240.48
+US,EAGLEPASS,TX,28.5841,-100.2545,23.74.2.7
+US,FORESTLAKE,MN,45.2627,-93.0169,107.14.38.218
+US,PONDERAY,ID,48.3056,-116.5325,184.27.179.165
+CZ,OLOMOUC,"",49.58,17.25,23.62.237.135
+IR,IMAM,"",36.70,48.81,184.27.45.150
+US,REXBURG,ID,43.7568,-111.6247,184.27.179.165
+US,WAUKESHA,WI,42.9721,-88.2283,107.14.38.218
+US,CHESTERLAND,OH,41.5320,-81.3349,107.14.38.218
+US,RICELAKE,WI,45.5296,-91.7231,23.74.8.24
+US,MEADVILLE,PA,41.6151,-80.1336,63.216.54.229
+US,BOCARATON,FL,26.3583,-80.0834,23.74.2.7
+US,OKEECHOBEE,FL,27.4513,-80.9004,184.27.45.157
+NL,BRUNSSUM,"",50.95,5.97,92.122.189.85
+GB,COLCHESTER,EN,51.88,0.90,88.221.87.112
+NL,SCHIPHOL,"",52.30,4.75,23.62.100.152
+BA,LUKA,"",43.95,18.48,194.25.95.219
+US,DELTONA,FL,28.9054,-81.2458,184.51.145.7
+US,ROCKHILL,SC,34.8891,-81.0214,184.51.35.215
+BR,SANTOS,SP,-23.95,-46.33,190.98.140.184
+BG,PLOVDIV,"",42.15,24.75,92.122.215.89
+US,ASHEBORO,NC,35.6532,-79.8468,209.18.41.27
+US,RATON,NM,36.7885,-104.4527,63.226.34.162
+US,VERSAILLES,KY,38.0184,-84.7389,63.216.54.216
+US,OPALOCKA,FL,25.9069,-80.2583,23.79.240.36
+AT,OBERPUCHENAU,"",48.32,14.23,195.145.147.109
+US,BILOXI,MS,30.4030,-88.8982,24.143.197.207
+US,ZANESVILLE,OH,39.9489,-82.0572,23.74.8.24
+US,ROY,UT,41.1733,-112.049,23.61.195.160
+DE,FLENSBURG,SH,54.78,9.43,194.25.95.214
+IR,BARAN,"",33.87,49.06,96.17.182.136
+US,PORTARTHUR,TX,29.7569,-94.1898,23.5.164.143
+US,OAKLEY,CA,37.9884,-121.6913,96.17.12.48
+CA,THORNHILL,ON,43.80,-79.42,72.246.43.237
+US,STONEMOUNTAIN,GA,33.7941,-84.2001,72.246.247.5
+US,SPRUCEPINE,NC,35.8996,-82.076,96.16.12.228
+US,PLEASANTVILLE,NY,41.1279,-73.7929,184.51.125.68
+US,SLATINGTON,PA,40.7371,-75.6374,23.67.242.156
+US,ENCINO,CA,34.1566,-118.5233,184.50.26.194
+US,STEELE,ND,46.8514,-99.9609,23.63.227.214
+US,WATERBURY,CT,41.5584,-73.0516,65.113.249.8
+US,CITRUSHEIGHTS,CA,38.6954,-121.2709,23.212.52.82
+RS,OBRENOVAC,"",43.04,22.72,2.20.45.104
+US,MOUNTGILEAD,OH,40.5633,-82.7592,65.113.249.11
+US,TEXASCITY,TX,29.3796,-94.9168,96.17.163.161
+US,GREENWELLSPRINGS,LA,30.5283,-91.0015,96.17.153.157
+US,AMELIA,OH,39.0167,-84.2069,165.254.207.111
+US,ANGOLA,IN,41.6594,-85.0055,23.67.60.220
+US,VALPARAISO,IN,41.4608,-87.0555,184.27.120.65
+JP,TOSHIMA,13,34.52,139.28,72.246.184.81
+US,MUSKEGON,MI,43.2355,-86.2532,23.67.60.223
+RU,NIJNIINOVGOROD,"",56.33,44.00,80.239.222.190
+KZ,TALDYK,"",54.65,67.80,23.14.94.214
+IT,NAPOLI,"",40.83,14.25,195.10.50.196
+US,COLLIERVILLE,TN,35.0596,-89.6789,23.79.240.48
+GB,BURY,EN,50.90,-0.57,195.245.125.107
+US,EASTTROY,WI,42.7945,-88.4154,107.14.38.227
+PL,GRZEGORZ,"",53.23,18.68,2.22.52.102
+UA,EUPATORIA,CRIMEA,45.20,33.36,92.122.215.89
+US,FARGO,ND,46.9259,-96.8507,165.254.114.164
+FR,PUGETVILLE,"",43.28,6.13,92.122.189.85
+SA,DHAHRAN,"",26.30,50.13,2.20.249.12
+KH,THMEY,"",11.80,104.93,23.76.205.90
+AU,DUBBO,NSW,-32.25,148.62,104.72.70.95
+CN,PUTIAN,FJ,25.44,119.01,184.50.87.178
+US,BLUESPRINGS,MO,39.0167,-94.2817,23.77.234.35
+US,PLAQUEMINE,LA,30.2546,-91.307,96.17.153.157
+DE,WITTEN,NW,51.43,7.33,194.25.95.212
+US,LOSALAMITOS,CA,33.7944,-118.0653,184.50.26.204
+ID,BATAM,"",1.08,104.03,23.0.162.40
+US,PENDLETON,OR,45.6098,-118.7308,184.27.179.159
+ID,CILEGON,"",-6.02,106.05,111.94.254.81
+CA,LEAMINGTON,ON,42.05,-82.58,72.246.43.215
+US,BARSTOW,CA,35.1476,-117.2068,184.50.26.204
+CA,WHITEHORSE,YT,60.72,-135.05,184.150.187.236
+US,HANNIBAL,MO,39.7145,-91.4209,204.93.47.216
+US,SOUTHBOSTON,VA,36.7012,-79.0269,184.29.107.38
+US,DESERTHOTSPRINGS,CA,33.9562,-116.5278,184.50.26.204
+PH,BAYAN,"",14.82,121.05,202.78.83.175
+FR,LECANNET,"",43.57,7.02,88.221.83.140
+US,EASTSTROUDSBURG,PA,41.0716,-75.148,184.26.44.42
+US,PORTAGE,WI,43.5939,-89.4754,23.74.8.8
+NI,MANAGUA,"",12.15,-86.27,184.26.44.38
+US,OPP,AL,31.2505,-86.2666,184.51.35.226
+US,KALISPELL,MT,48.0396,-113.5304,184.27.179.187
+US,FREEHOLD,NJ,40.2229,-74.3007,184.51.125.68
+US,SUWANEE,GA,34.0498,-84.0681,184.28.127.58
+IN,GOA,GA,15.50,73.92,23.211.135.66
+US,FERNANDINABEACH,FL,30.6056,-81.5268,23.79.240.36
+US,BELLEFONTE,PA,40.9455,-77.7398,23.192.161.21
+US,CALLAHAN,FL,30.5784,-81.8357,23.79.240.36
+RU,TVER,"",56.86,35.89,165.254.1.206
+US,ALGONQUIN,IL,42.1655,-88.2877,23.67.60.223
+TW,NANKANG,"",25.05,121.60,61.220.62.175
+US,LAQUINTA,CA,33.6713,-116.2873,184.50.26.201
+US,BARBERTON,OH,41.0203,-81.628,65.113.249.8
+US,WAYNESVILLE,NC,35.5777,-83.0002,23.79.240.48
+DE,PASSAU,BY,48.58,13.48,195.145.147.107
+VN,QUAN,"",18.43,105.75,23.76.205.111
+CH,LAUSANNE,"",46.53,6.67,193.247.167.211
+AR,ROQUESAENZPENA,"",-26.78,-60.45,200.123.201.219
+US,DONALDSONVILLE,LA,30.1206,-91.0306,23.215.15.32
+NZ,NEWPLYMOUTH,"",-39.07,174.08,219.88.186.165
+US,DEVILSLAKE,ND,48.1943,-98.7957,107.14.38.224
+IN,VASAI,MH,19.35,72.80,23.211.135.110
+RU,OREL,"",55.73,34.10,217.212.227.31
+US,LACRESCENTA,CA,34.2360,-118.2448,23.216.10.78
+US,COPPELL,TX,32.9610,-96.986,23.215.15.9
+US,ORLANDPARK,IL,41.6163,-87.8577,23.67.60.222
+US,PORTSAINTLUCIE,FL,27.2963,-80.2966,23.79.240.48
+UA,KRIVOYROG,"",47.92,33.35,23.14.94.224
+US,OPELIKA,AL,32.5952,-85.3164,23.79.240.36
+IS,REYKJAVIK,"",64.15,-21.95,23.212.108.8
+MX,TORREON,COA,25.55,-103.43,173.223.52.67
+ZA,POTCHEFSTROOM,"",-26.72,27.10,41.193.163.53
+AU,BROADMEADOWS,VIC,-37.67,144.90,184.84.221.85
+US,GRAMERCY,LA,30.1097,-90.6848,96.17.153.162
+US,PHILIPSBURG,PA,40.8621,-78.166,23.67.242.139
+US,BELCHERTOWN,MA,42.2771,-72.4022,23.67.244.224
+US,ORANGECITY,FL,28.9410,-81.3069,23.33.186.134
+US,LELAND,NC,34.2757,-78.1004,209.18.41.27
+KH,SIHANOUK,"",10.63,103.50,203.106.85.13
+GR,IRAKLIO,"",37.80,22.72,85.205.31.89
+US,JEFFERSON,GA,34.1004,-83.5698,63.216.54.231
+US,WALTERBORO,SC,32.8889,-80.7102,184.51.35.226
+DE,TETTNANG,BW,47.67,9.60,23.14.94.224
+IR,RAZAVI,"",34.28,58.47,165.254.96.242
+AR,CORDOBA,"",-31.40,-64.18,200.123.201.215
+CN,LANZHOU,GS,36.06,103.79,72.246.191.19
+US,POWDERSPRINGS,GA,33.8752,-84.6983,23.79.240.48
+US,BOURBONNAIS,IL,41.1818,-87.8739,23.67.60.222
+CI,ABIDJAN,"",5.32,-4.03,195.245.125.107
+US,WESTDESMOINES,IA,41.5662,-93.743,173.197.194.166
+US,CLARKSSUMMIT,PA,41.4656,-75.7341,184.25.157.155
+US,SAINTPETER,MN,44.3784,-94.0784,23.79.255.149
+US,NEWBREMEN,OH,40.4590,-84.3985,23.74.8.8
+US,FORTMORGAN,CO,40.1574,-103.8158,107.14.32.235
+CN,FOSHAN,GD,23.03,113.12,184.84.239.175
+AT,LOHNSBURG,"",48.15,13.40,84.53.146.39
+PL,GLIWICE,"",50.28,18.67,2.22.52.109
+HK,QUARRYBAY,"",22.28,114.22,23.76.205.90
+US,LUMBERTON,NC,34.6231,-78.9771,209.18.41.27
+FI,PORI,"",61.48,21.78,23.215.15.9
+US,BYRON,GA,32.6425,-83.775,23.212.53.64
+RU,KURSK,"",51.73,36.19,2.21.240.40
+MW,BLANTYRE,"",-15.78,35.00,217.89.107.166
+US,WESTWEGO,LA,29.9137,-90.2078,23.215.15.9
+AU,BENTLEY,WA,-32.00,115.92,23.62.224.33
+US,YAZOOCITY,MS,32.8273,-90.5829,23.215.15.32
+CD,KINSHASA,"",-4.33,15.31,77.67.40.172
+KZ,AKTOBE,"",43.98,78.80,80.239.149.123
+PL,ZYCHLIN,"",52.25,19.62,80.239.222.190
+US,FAIRBORN,OH,39.8173,-84.0025,107.14.38.218
+US,BLUEISLAND,IL,41.6641,-87.6855,107.14.38.218
+US,LISLE,IL,41.7894,-88.0823,23.67.60.223
+GB,LUTON,EN,51.88,-0.42,88.221.87.94
+US,NOLENSVILLE,TN,35.9350,-86.6688,165.254.138.175
+US,LACONIA,NH,43.5670,-71.4823,165.254.48.154
+US,SHOWLOW,AZ,34.0940,-110.0867,65.116.149.102
+US,GRIFFITH,IN,41.5177,-87.4208,107.14.38.218
+US,SCHENECTADY,NY,42.8148,-73.9393,72.247.10.237
+IR,GOLESTAN,"",35.77,51.46,80.239.149.123
+US,BEAUFORT,SC,32.4316,-80.67,165.254.138.165
+TR,BURSA,"",40.58,30.90,77.67.29.116
+JP,YOKKAICHI,24,34.97,136.62,117.104.139.162
+US,KEARNY,NJ,40.7563,-74.1217,184.26.44.40
+BR,CUIABA,MT,-15.58,-56.08,72.246.216.144
+US,ALPINE,CA,32.8087,-116.7197,184.50.26.204
+MA,RABAT,"",34.03,-6.83,95.100.171.27
+US,ROCKLAND,ME,44.1308,-69.1301,24.143.199.156
+US,HARRISBURG,PA,40.2628,-76.8813,23.67.242.139
+KZ,AKTAU,"",48.03,72.83,23.14.94.224
+US,SHREWSBURY,MA,42.2859,-71.7148,63.238.85.161
+US,PALMETTO,FL,27.5213,-82.5728,23.33.186.101
+US,LATHAM,NY,42.7511,-73.7732,107.14.38.217
+TR,ERCIYES,"",38.63,35.58,80.15.235.161
+US,EASTON,PA,40.7421,-75.2249,184.29.107.38
+SG,KALLANG,"",1.33,103.87,96.17.180.175
+US,OZARK,MO,36.9964,-93.1892,209.170.117.178
+US,MIDDLEBURY,VT,43.9961,-73.1846,184.29.107.20
+FR,ALGRANGE,"",49.35,6.05,88.221.15.110
+US,HOMOSASSA,FL,28.7478,-82.5258,23.34.56.147
+US,AGOURAHILLS,CA,34.1403,-118.7625,184.87.195.99
+CN,ZHUZHOU,HN,27.83,113.15,72.246.191.16
+PL,KALISZ,"",52.95,20.65,2.22.52.101
+US,DENHAMSPRINGS,LA,30.5870,-90.9124,23.212.53.64
+DE,KRUMMESSE,SH,53.78,10.65,92.122.207.164
+US,TARPONSPRINGS,FL,28.1455,-82.7568,184.27.45.157
+US,GILBERTSVILLE,PA,40.3096,-75.5833,184.26.44.38
+US,VALRICO,FL,27.9126,-82.237,23.33.186.101
+IN,MANDAPAM,TN,9.28,79.12,96.17.182.130
+PL,PILAWAGORNA,"",50.70,16.73,2.22.61.99
+US,SHAKOPEE,MN,44.7514,-93.5146,63.151.29.12
+IT,RIMINI,"",44.06,12.58,213.144.173.198
+US,WAYNESBURG,PA,39.8611,-80.1706,63.216.54.229
+US,GRANBURY,TX,32.4158,-97.782,204.93.47.216
+US,WALTHILL,NE,42.1478,-96.478,23.79.255.149
+IT,PIEMONTE,"",42.78,12.55,2.18.240.95
+US,NORTHFORTMYERS,FL,26.7437,-81.9862,23.79.240.36
+SE,HELSINGBORG,M,56.05,12.70,23.65.29.106
+US,BOONE,NC,36.2085,-81.6605,23.79.240.36
+US,LOSBANOS,CA,36.9711,-120.9668,23.212.52.93
+DZ,TIZIOUZOU,"",36.72,4.05,90.84.53.194
+CA,BRANTFORD,ON,43.13,-80.27,72.246.43.215
+US,NEWRIVER,AZ,33.8763,-112.0502,184.50.26.194
+FR,MONTESSON,"",48.92,2.15,2.16.117.190
+ID,RAYA,"",1.08,118.53,23.0.162.54
+US,LOCUSTGROVE,GA,33.3564,-84.1119,72.246.247.5
+US,WESTNEWYORK,NJ,40.7879,-74.0112,184.26.44.38
+US,NORTHOLMSTED,OH,41.4153,-81.9188,23.67.242.139
+US,CUDAHY,WI,42.9465,-87.8638,107.14.38.217
+US,POSTFALLS,ID,47.7405,-116.9576,184.26.93.116
+US,INVERNESS,FL,28.8296,-82.2553,23.33.186.101
+US,SKIATOOK,OK,36.3833,-96.0366,165.254.138.175
+PL,ZAMBROW,"",52.98,22.25,2.22.52.109
+IR,LIR,"",34.70,49.75,2.22.52.105
+US,CLOQUET,MN,46.7232,-92.5588,65.113.249.11
+US,MOCKSVILLE,NC,35.9339,-80.5455,209.18.41.23
+US,PEKIN,IL,40.5452,-89.6011,184.27.120.65
+AU,CAIRNS,QLD,-16.92,145.77,23.209.183.61
+HU,KECSKEMET,"",46.90,19.78,72.247.10.241
+DK,EM,"",57.35,9.92,2.21.240.61
+RO,BRASOV,"",45.63,25.58,2.22.52.102
+US,GRANDVIEW,WA,46.2604,-119.9241,67.131.104.14
+US,HIGHPOINT,NC,35.9808,-80.1272,184.27.45.150
+US,HAMPSTEAD,NC,34.4359,-77.683,23.79.240.37
+CO,BELLO,"",6.33,-75.55,23.215.15.22
+IR,PARS,"",35.74,51.53,23.62.238.220
+US,SENATOBIA,MS,34.6336,-89.8203,96.17.153.162
+RO,ORADEA,"",47.07,21.93,81.196.26.198
+SE,GOTEBORG,O,57.72,11.97,213.155.156.208
+US,WINDHAM,ME,43.7950,-70.4037,165.254.35.197
+US,WEYMOUTH,MA,42.2076,-70.9575,184.25.109.196
+US,MASCOUTAH,IL,38.4590,-89.7628,204.93.47.220
+US,SANCLEMENTE,CA,33.4046,-117.5066,23.212.53.64
+US,RISON,AR,33.9470,-92.1633,23.74.8.24
+US,OSHKOSH,WI,43.9500,-88.5387,184.50.26.179
+HU,SZEGED,"",46.25,20.17,23.14.94.214
+TR,HATAY,"",36.23,36.12,193.45.15.198
+IN,MALIANDMUNJERI,MH,18.53,73.87,117.239.189.99
+JP,UTSUNOMIYA,09,36.55,139.87,96.7.251.95
+US,SEGUIN,TX,29.5278,-97.9363,96.17.163.161
+FR,ROUVIGNIES,"",50.33,3.43,2.16.117.190
+GP,POINTEAPITRE,"",16.23,-61.52,184.26.44.38
+US,FORTEUSTIS,VA,37.1626,-76.5808,23.220.148.122
+US,GOSHEN,NY,41.3906,-74.3406,24.143.199.188
+US,LAURENS,SC,34.4899,-82.0542,23.79.240.48
+US,SUMTER,SC,33.9242,-80.1986,209.18.41.23
+US,GLENDIVE,MT,47.0499,-104.5596,184.51.35.215
+US,VICKSBURG,MI,42.1149,-85.4789,23.67.60.223
+US,MIDVALE,UT,40.6150,-111.8913,184.84.180.68
+FR,OUISTREHAM,"",49.28,-0.25,2.16.117.190
+US,ENUMCLAW,WA,47.1782,-121.6415,184.27.179.159
+US,NORTHANSON,ME,44.9516,-69.9465,165.254.35.182
+UA,MAKEEVKA,"",48.03,37.97,2.21.240.61
+US,CORSICANA,TX,32.0635,-96.4417,184.27.179.181
+JP,NIHO,35,34.22,131.55,117.104.139.162
+US,DILLON,MT,45.1146,-112.8794,107.14.32.235
+US,FORTDODGE,IA,42.5075,-94.2531,63.151.29.15
+US,BADAXE,MI,43.7988,-82.998,65.113.249.8
+US,KILLINGWORTH,CT,41.3791,-72.5783,184.25.109.200
+FR,CORBEIL,"",48.60,2.48,2.16.117.200
+US,WESTORANGE,NJ,40.7895,-74.2629,184.26.44.38
+US,ZEPHYRHILLS,FL,28.2333,-82.1815,23.34.56.142
+PL,WYRZYSK,"",53.17,17.28,2.22.52.102
+IN,KAKINADA,AP,16.93,82.22,23.205.118.109
+CZ,LITOMYSL,"",49.87,16.32,23.62.237.135
+JP,TOKAI,23,35.03,136.89,23.3.104.15
+US,ROLLA,MO,37.9394,-91.763,63.216.54.236
+CA,SHERBROOKE,QC,45.40,-71.90,204.93.33.141
+TH,SONGKHLA,"",7.20,100.60,61.19.12.177
+US,DODGECITY,KS,37.6960,-100.1054,23.215.15.9
+BA,SARAJEVO,"",43.85,18.38,23.14.94.224
+US,WAGONER,OK,35.9683,-95.3871,23.5.164.146
+US,TUCUMCARI,NM,35.0485,-103.7548,64.129.104.132
+US,THURMONT,MD,39.5936,-77.4215,23.192.161.16
+AU,WARRAGUL,VIC,-38.17,145.93,210.11.142.65
+US,ITASCA,IL,41.9751,-88.0186,23.67.60.220
+US,FORTCAMPBELL,KY,36.6606,-87.4578,23.212.53.64
+CH,BASEL,"",47.57,7.60,195.145.147.109
+US,HALLANDALE,FL,25.9808,-80.1486,23.79.240.36
+US,EASTAURORA,NY,42.7704,-78.5853,209.18.41.27
+US,ROYERSFORD,PA,40.2034,-75.5319,23.67.242.156
+US,SHALLOTTE,NC,33.9593,-78.431,184.51.35.215
+US,OAKHARBOR,WA,48.3182,-122.6341,23.212.59.64
+IE,PORTLAOISE,"",53.03,-7.30,88.221.222.34
+US,JERSEYVILLE,IL,39.1259,-90.3475,96.17.14.16
+US,LITITZ,PA,40.1769,-76.295,184.25.157.155
+US,BUTTE,MT,45.9274,-112.5042,165.254.1.165
+RO,ONESTI,"",46.25,26.75,81.196.26.236
+US,MONCKSCORNER,SC,33.1483,-80.0528,184.51.35.226
+SE,FALKENBERG,N,56.90,12.50,2.21.240.61
+US,BELLMAWR,NJ,39.8669,-75.093,23.67.60.220
+US,HOUGHTON,MI,47.1004,-88.5759,184.85.215.165
+KH,BOEUNG,"",12.43,105.12,23.15.10.106
+US,REEDSBURG,WI,43.5282,-90.0016,184.85.215.165
+HK,KOWLOONTONG,"",22.33,114.18,23.76.205.111
+US,TILTON,NH,43.4812,-71.5745,184.25.109.196
+US,ROBERTSDALE,AL,30.6097,-87.6111,184.51.35.215
+US,JACKSONHEIGHTS,NY,40.7514,-73.8836,209.18.41.27
+US,SNELLVILLE,GA,33.7958,-83.9918,23.79.240.36
+US,FORTLUPTON,CO,40.0874,-104.8664,23.212.53.75
+CA,MONCTON,NB,46.08,-64.77,209.148.192.57
+US,CLARKSTON,WA,46.2148,-117.2463,165.254.144.32
+US,LITTLEFALLS,NJ,40.8835,-74.2057,184.26.44.40
+PL,KUTNO,"",52.23,19.37,2.22.52.101
+US,WEBSTER,MN,44.5239,-93.3702,23.67.60.220
+ZW,ZIMBABWE,"",-20.27,30.92,41.193.163.53
+DE,HERNE,NW,51.55,7.22,23.14.94.220
+PL,RZESZOW,"",50.05,22.00,77.67.96.116
+TH,PATHUMTHANI,"",14.02,100.53,61.19.12.79
+US,ELSA,TX,26.2988,-97.9827,204.2.223.91
+CH,WIL,"",47.60,8.50,92.122.215.67
+US,FERNLEY,NV,39.5869,-119.1525,23.61.195.149
+US,VANDALIA,OH,39.8973,-84.2232,107.14.38.218
+US,HURON,SD,44.3587,-98.2248,107.14.38.224
+US,HORNLAKE,MS,34.9498,-90.0305,184.84.180.98
+US,OAKHURST,CA,37.5934,-119.4077,173.223.52.67
+US,MILAN,TN,35.9258,-88.7624,204.2.243.132
+IR,SISTAN,"",36.95,49.75,23.14.94.224
+JP,AOMORI,02,40.82,140.75,72.246.191.16
+US,LAYTON,UT,41.1018,-111.9067,184.84.180.101
+BG,BANSKO,"",41.83,23.48,2.20.142.173
+FR,AX,"",42.72,1.83,23.200.87.58
+US,ALLIANCE,OH,40.9181,-81.1273,96.6.47.120
+US,HUGO,OK,34.0348,-95.5268,96.16.7.101
+PL,KOZIENICE,"",51.58,21.57,2.22.52.102
+US,FORESTPARK,GA,33.6133,-84.3728,23.212.53.64
+US,KILLEN,AL,34.9168,-87.5035,23.220.100.224
+BZ,BELIZECITY,"",17.48,-88.18,23.74.2.7
+KR,POHANG,"",36.03,129.37,125.56.214.147
+US,SOUTHMILWAUKEE,WI,42.9118,-87.8624,107.14.38.227
+US,WINTERSPRINGS,FL,28.6860,-81.2771,23.34.56.147
+US,MEXICO,MO,39.1882,-91.8924,204.93.47.220
+US,BOZEMAN,MT,45.6891,-110.9295,107.14.32.228
+KZ,URALSK,"",51.23,51.37,2.20.142.173
+US,WESTHAVEN,CT,41.2716,-72.9666,184.25.109.213
+BE,OVERHEID,"",51.07,4.27,23.62.100.152
+US,GLENALLEN,VA,37.6656,-77.5069,184.26.44.38
+US,BROCKPORT,NY,43.2485,-77.9306,107.14.38.217
+US,MAQUOKETA,IA,42.1200,-90.7234,165.254.207.117
+US,MARTINSFERRY,OH,40.1258,-80.7518,23.192.161.21
+US,ROLLINGMEADOWS,IL,42.0703,-88.0209,107.14.38.218
+US,CYNTHIANA,KY,38.4145,-84.2859,23.79.240.48
+US,DANVERS,MA,42.5739,-70.9505,184.25.109.200
+US,ZILLAH,WA,46.4400,-120.2284,184.27.179.181
+RS,BEOGRAD,"",44.82,20.47,2.20.45.104
+US,SANTAFESPRINGS,CA,33.9363,-118.0653,184.50.26.194
+FR,ANNECY,"",45.90,6.12,92.122.189.85
+US,HEBERCITY,UT,40.2386,-111.1499,23.61.195.149
+US,LENOIR,NC,35.9137,-81.5393,23.79.240.48
+JP,FUKUSHIMA,07,37.75,140.47,72.246.184.92
+US,MOORESVILLE,NC,35.5822,-80.8122,209.18.41.27
+US,LAPORTE,TX,29.6785,-95.0483,96.17.163.165
+MX,QUERETARO,QUE,20.60,-100.38,187.141.2.151
+US,MURRYSVILLE,PA,40.4616,-79.6658,23.192.161.16
+US,NEWBRUNSWICK,NJ,40.4861,-74.4473,184.26.44.42
+US,HADDONHEIGHTS,NJ,39.8789,-75.0646,23.67.242.139
+US,FAIRBANKS,AK,64.5037,-147.6591,23.212.59.64
+NZ,PAPAKURA,"",-37.08,174.95,219.88.186.167
+UA,KHERSON,"",46.63,32.60,217.212.227.25
+AU,RANDWICK,NSW,-33.92,151.24,23.62.8.21
+US,SOUTHBEND,IN,41.6699,-86.2535,23.63.227.227
+US,MERIDIANVILLE,AL,34.8710,-86.5547,23.220.100.223
+US,BREAUXBRIDGE,LA,30.2731,-91.9325,23.215.15.9
+GB,GATESHEAD,EN,54.95,-1.62,88.221.87.112
+US,STEVENSONRANCH,CA,34.3795,-118.5754,63.233.112.196
+IT,POGGIBONSI,"",43.47,11.15,77.67.29.116
+CA,CORNERBROOK,NF,48.95,-57.93,209.148.192.57
+DE,GREIFSWALD,MV,54.10,13.38,80.157.150.201
+US,PARAMOUNT,CA,33.8963,-118.1642,184.50.26.194
+US,GOOCHLAND,VA,37.7179,-78.0059,184.26.44.38
+US,BEACH,ND,47.0809,-103.8785,63.216.54.231
+US,LEWISCENTER,OH,40.1839,-82.9843,107.14.38.224
+CA,OLIVER,BC,49.18,-119.55,184.27.179.187
+US,SONORA,TX,30.4983,-100.5382,23.215.15.9
+ID,BINTANG,"",-7.25,107.20,23.0.162.21
+US,SLOCOMB,AL,31.0914,-85.5835,184.27.45.157
+GI,GIBRALTAR,"",36.13,-5.35,92.123.73.233
+BA,BIHAC,"",44.82,15.87,23.14.94.224
+JP,HIMEJI,28,34.82,134.70,23.3.74.113
+US,GREER,SC,34.8978,-82.2584,72.246.247.5
+US,LEWISTOWN,PA,40.6073,-77.5812,23.192.161.30
+US,LINCOLNTON,NC,35.4951,-81.2237,23.79.240.48
+US,MISHAWAKA,IN,41.6161,-86.1361,23.67.60.220
+US,ISLEOFPALMS,SC,32.8046,-79.7534,23.79.240.36
+FR,TAVERNY,"",49.03,2.22,2.16.117.200
+RU,ROSSIYA,"",54.82,32.42,92.122.189.114
+FR,SAINTEGENEVIEVEDESBOIS,"",48.63,2.33,2.20.243.42
+US,YELM,WA,46.8659,-122.5344,23.212.59.63
+US,ALLSTON,MA,42.3585,-71.13,184.29.107.38
+US,CRYSTALCITY,MO,38.2311,-90.378,204.93.47.220
+US,LAKESIDEMARBLEHEAD,OH,41.5249,-82.7767,23.74.8.24
+US,MENTOR,OH,41.6763,-81.3297,107.14.38.218
+US,RICHLANDCENTER,WI,43.4015,-90.4109,184.85.215.165
+US,SOUTHAVEN,MS,34.9597,-89.9817,23.212.53.64
+US,WALTHAM,MA,42.3876,-71.2411,184.28.17.76
+IR,SEPAHAN,"",35.67,51.17,184.25.157.155
+US,TEMPLE,TX,31.0795,-97.3287,107.14.43.29
+US,DINUBA,CA,36.5216,-119.3869,23.212.52.79
+US,SAINTALBANS,VT,44.8111,-73.0813,23.192.161.30
+PL,TORUN,"",53.03,18.60,80.239.149.123
+US,NORTHWILKESBORO,NC,36.1585,-81.1478,23.79.240.36
+ID,PAKANBARU,"",0.53,101.45,118.98.37.99
+US,LEVELLAND,TX,33.6122,-102.3901,107.14.36.199
+SE,ESKILSTUNA,D,59.37,16.50,2.21.240.61
+ZA,PAROW,"",-33.90,18.60,165.165.46.36
+US,MCALESTER,OK,34.9351,-95.8929,174.76.226.117
+US,MOULTRIE,GA,31.1855,-83.7469,63.216.54.229
+FR,NEUILLYPLAISANCE,"",48.87,2.52,2.16.117.190
+AU,WENTWORTH,NSW,-34.12,141.92,210.11.142.64
+US,CLAYTON,NC,35.6321,-78.4269,209.18.41.23
+US,MILLEDGEVILLE,GA,33.0769,-83.3032,63.216.54.231
+US,BRYANSROAD,MD,38.6499,-77.0865,23.192.161.16
+IR,ALBORZ,"",34.73,50.97,23.14.94.224
+RO,ZALAU,"",47.20,23.05,80.239.222.190
+US,KANNAPOLIS,NC,35.5043,-80.6706,209.18.41.27
+HK,NORTHPOINT,"",22.30,114.20,184.84.239.186
+US,NOTREDAME,IN,41.7197,-86.2504,107.14.32.235
+PY,FERNANDODELAMORA,"",-25.32,-57.60,200.91.22.117
+US,BRUSH,CO,40.1479,-103.5597,173.197.194.159
+CN,SUQIAN,JS,33.95,118.30,23.15.10.91
+US,CHITTENANGO,NY,43.0618,-75.8688,107.14.38.217
+ZA,POINT,"",-29.87,31.05,41.193.163.45
+US,WESTFARGO,ND,46.8625,-96.9269,107.14.38.218
+TR,ANKARA,"",39.94,32.86,2.20.142.166
+GA,LIBREVILLE,"",0.38,9.45,195.245.125.249
+IN,AGRA,UP,27.18,78.02,213.248.108.233
+US,SUNPRAIRIE,WI,43.2012,-89.2037,184.85.215.170
+DE,CLAUSTHALZELLERFELD,NI,51.80,10.33,195.95.193.132
+US,GUALALA,CA,38.8361,-123.4304,23.63.227.214
+PL,BIALYSTOK,"",53.13,23.15,80.157.149.129
+IN,KARUR,TN,10.95,78.08,96.17.182.136
+US,TRUTHORCONSEQUENCES,NM,33.1866,-106.8454,23.212.53.64
+US,CLEMSON,SC,34.6740,-82.8212,64.86.201.118
+DE,LAUCHHAMMER,BB,51.50,13.80,195.95.193.150
+US,DAVISON,MI,43.0361,-83.513,23.63.227.227
+JP,SENDAI,04,38.26,140.89,117.104.139.136
+US,MINDEN,NE,40.5009,-98.902,23.212.53.64
+US,OCONOMOWOC,WI,43.1140,-88.4931,107.14.38.217
+US,RUSKIN,FL,27.7115,-82.4202,23.33.186.134
+US,QUEENSVILLAGE,NY,40.7303,-73.748,184.26.44.42
+US,BELPRE,OH,39.3164,-81.6086,107.14.38.227
+US,HARKERHEIGHTS,TX,31.0283,-97.6473,107.14.43.29
+US,LINTON,IN,39.0608,-87.1852,23.67.60.220
+SE,BOLLNAS,X,61.35,16.37,2.21.240.40
+US,WALLEDLAKE,MI,42.5503,-83.474,23.67.60.222
+US,CHIPPEWAFALLS,WI,44.9743,-91.4379,65.113.249.8
+DK,SKANDERBORG,"",56.03,9.93,23.65.29.93
+DE,FRIEDRICHSHAFEN,BW,47.65,9.48,23.14.94.224
+JP,HAKODATE,01,41.75,140.72,23.3.104.15
+US,GIRARD,OH,41.1741,-80.6779,107.14.38.217
+TR,ADANA,"",38.63,28.88,193.45.15.199
+MZ,MAPUTO,"",-25.97,32.59,165.165.46.38
+US,INVERGROVEHEIGHTS,MN,44.8348,-93.0357,23.67.60.220
+US,PINEVILLE,KY,36.7417,-83.6911,173.197.192.214
+US,BRAZIL,IN,39.5158,-87.1262,23.63.227.214
+GB,OVER,EN,52.32,0.02,195.245.125.249
+ID,RIAU,"",-1.72,105.93,23.0.162.40
+CN,SHANGXI,ZJ,29.30,119.90,23.76.205.111
+US,BALDWINCITY,KS,38.8017,-95.2855,23.67.60.223
+US,PROSPER,TX,33.2340,-96.7848,184.28.23.4
+US,NORMAL,IL,40.5373,-88.9869,23.67.60.222
+US,GILLETTE,WY,44.4735,-105.5945,23.212.53.75
+US,POTEAU,OK,35.0533,-94.5362,23.215.15.32
+US,FRIENDSWOOD,TX,29.5125,-95.188,96.17.163.161
+US,HOLDENVILLE,OK,35.0789,-96.319,96.16.7.101
+US,NEWPORTRICHEY,FL,28.2352,-82.7347,23.34.56.142
+NL,BREDA,"",51.57,4.80,92.122.189.114
+TR,KADIKOY,"",40.82,32.83,80.15.235.163
+KZ,KOKCHETAV,"",53.28,69.39,213.155.156.207
+US,METHUEN,MA,42.7346,-71.189,23.67.244.240
+NG,LIKE,"",6.90,7.48,95.101.2.122
+CZ,FRYDEKMISTEK,"",49.68,18.33,23.62.237.133
+PL,PODGORNE,"",53.42,21.78,61.111.58.229
+US,PIQUA,OH,40.1702,-84.2793,107.14.38.218
+IR,ILAM,"",33.64,46.43,80.239.149.123
+UA,SIMFEROPOL,CRIMEA,44.95,34.10,2.22.52.101
+US,VANBUREN,AR,35.4580,-94.2992,174.76.226.117
+IR,ARDABIL,"",38.25,48.30,23.62.238.215
+US,BANGOR,ME,44.8521,-68.8311,107.14.38.224
+FR,VELIZY,"",48.80,2.18,23.200.87.59
+US,BELTSVILLE,MD,39.0347,-76.9076,184.28.17.55
+JP,ASHIKAGA,09,36.33,139.45,23.3.104.20
+US,LOSALAMOS,NM,35.8375,-106.349,23.212.52.88
+CA,ALLISTON,ON,44.15,-79.87,72.246.43.215
+US,FOLSOM,CA,38.6648,-121.1414,96.17.12.48
+US,SCOTTSBORO,AL,34.7061,-86.0958,184.51.35.215
+US,DURANT,OK,34.0185,-96.3864,184.28.23.4
+MX,PATZCUARO,MIC,19.52,-101.60,23.212.53.64
+IN,ULUBARI,AS,26.50,90.42,23.57.76.18
+GB,STEVENAGE,EN,51.92,-0.22,23.67.255.158
+US,BETHESDA,MD,38.9806,-77.1008,23.192.161.16
+ID,BANTEN,"",-6.05,106.15,23.0.162.21
+RU,KOPEYSK,"",55.12,61.62,2.21.240.61
+US,PAINESVILLE,OH,41.6851,-81.2077,96.17.9.8
+US,PICKENS,SC,34.9245,-82.7166,72.246.247.5
+US,SANCARLOS,CA,37.4970,-122.2756,23.212.52.79
+US,CHARLESTOWN,WV,39.2635,-77.8778,23.192.161.21
+RU,NALCHIK,"",43.50,43.62,2.21.240.61
+US,BLAKELY,GA,31.3824,-84.9419,63.216.54.236
+US,STRONGSVILLE,OH,41.3148,-81.8093,96.17.9.14
+US,WESTHENRIETTA,NY,43.0409,-77.6888,107.14.38.227
+US,GENESEE,MI,43.1100,-83.6218,65.113.249.8
+PL,NOWYTOMYSL,"",52.32,16.15,2.22.61.99
+US,STATENISLAND,NY,40.6308,-74.0923,24.143.199.188
+US,BEEBE,AR,35.1238,-91.9422,96.17.14.15
+MO,TAIPA,"",22.15,113.55,202.175.5.87
+ID,BEKASI,"",-6.23,106.98,202.43.190.239
+US,HOPKINSVILLE,KY,36.8832,-87.4597,23.220.100.224
+US,OVERTON,NV,36.5809,-114.605,64.145.95.145
+RO,PITESTI,"",44.85,24.87,81.196.26.236
+US,WISCONSINRAPIDS,WI,44.3431,-89.7334,65.113.249.8
+US,DANAPOINT,CA,33.4774,-117.7048,64.86.201.118
+US,ELKHART,IN,41.7235,-85.9764,23.74.8.8
+US,BIGSPRING,TX,32.2854,-101.4495,23.5.164.143
+CA,SAINTLAMBERT,QC,45.48,-73.50,67.69.197.160
+US,MATTESON,IL,41.5063,-87.7446,107.14.38.218
+US,HANOVER,NH,43.7256,-72.2368,184.25.109.200
+CA,HULL,QC,45.43,-75.73,67.69.197.160
+AU,WERRIBEE,VIC,-37.90,144.67,184.84.221.87
+US,DELRAYBEACH,FL,26.4576,-80.0806,23.79.240.37
+US,MCCOMB,MS,31.1693,-90.3678,165.254.138.175
+US,MACHESNEYPARK,IL,42.3589,-89.0409,107.14.38.217
+VN,DANANG,"",21.72,105.35,112.175.42.120
+US,EUREKA,IL,40.7102,-89.2521,23.74.8.24
+US,HARMONY,PA,40.8638,-80.1313,209.48.37.188
+US,COUNCILBLUFFS,IA,41.2146,-95.8574,23.79.255.153
+AR,FUNES,"",-32.92,-60.82,200.123.201.215
+US,BUDA,TX,30.0694,-97.8797,184.26.93.116
+MN,BAYANGOL,"",48.91,106.09,80.239.237.230
+US,FORESTCITY,NC,35.2700,-81.8676,23.79.240.36
+AT,ALKOVEN,"",48.28,14.10,195.145.147.109
+IT,GENOVA,"",44.42,8.95,193.45.15.198
+US,KITTANNING,PA,40.8196,-79.4288,184.26.44.40
+UA,KHMELNITSKIY,"",49.42,27.00,2.21.240.61
+KZ,SEMEY,"",50.41,80.23,80.239.222.169
+US,GARRETSON,SD,43.7606,-96.5516,23.63.227.223
+US,DUNKIRK,NY,42.4788,-79.3113,107.14.38.227
+ID,MATARAM,"",-7.17,106.67,23.0.162.54
+US,UTICA,MI,42.6730,-82.9952,23.67.60.223
+US,VERNAL,UT,40.1055,-109.4989,63.235.21.141
+US,KELLOGG,ID,47.7187,-116.0875,24.143.194.180
+IN,VISHAKHAPATNAM,AP,17.70,83.30,23.57.69.157
+DE,ISERLOHN,NW,51.37,7.70,92.122.207.179
+US,ALTUS,OK,34.6829,-99.3441,23.215.15.22
+US,BOLIVAR,MO,37.6066,-93.4143,63.216.54.236
+US,BERWYN,IL,41.8314,-87.7884,107.14.38.227
+US,WESTCOLUMBIA,SC,33.9973,-81.0998,64.129.104.132
+US,ELLENSBURG,WA,47.0155,-120.3114,184.27.179.159
+US,LOMITA,CA,33.7935,-118.3174,184.50.26.204
+US,OPELOUSAS,LA,30.5146,-92.101,23.79.240.36
+US,SICKLERVILLE,NJ,39.7334,-74.9786,23.67.242.139
+US,CRAWFORDSVILLE,IN,40.0313,-86.9257,65.113.249.11
+US,MURPHY,NC,35.1195,-84.1344,184.27.45.150
+RU,DAGOMYS,"",43.66,39.65,92.122.189.114
+MX,XALAPAENRIQUEZ,VER,19.53,-96.92,165.254.1.206
+US,LIBERTYLAKE,WA,47.6567,-117.0803,184.27.179.187
+US,EDGEWATER,FL,28.9786,-80.9236,184.51.145.22
+ID,SURAKARTA,"",-6.42,105.87,23.0.162.46
+US,NEWMILFORD,NJ,40.9338,-74.0194,23.67.242.139
+US,OXONHILL,MD,38.8052,-76.9958,23.192.161.16
+US,MORRISVILLE,PA,40.1994,-74.8145,184.27.45.150
+BG,DOBRICH,"",42.02,25.52,92.122.189.85
+US,BLUFFTON,SC,32.2534,-80.8971,165.254.138.165
+DE,SCHLEGEL,TH,50.40,11.62,46.33.70.97
+US,LACANADAFLINTRIDGE,CA,34.2241,-118.1106,23.216.10.54
+CA,LONGUEUIL,QC,45.53,-73.52,72.246.43.215
+US,LEESSUMMIT,MO,38.9333,-94.3253,23.77.234.11
+RU,KALININA,"",53.52,36.03,2.21.240.61
+US,CLAWSON,MI,42.5361,-83.1514,23.67.60.222
+US,WHEATRIDGE,CO,39.7756,-105.108,184.84.180.98
+US,SCOTTDALE,PA,40.1122,-79.5869,65.121.209.127
+NL,DRONTEN,"",52.53,5.72,92.122.189.114
+DE,BEIERFELD,SN,50.57,12.80,92.122.215.67
+AU,TUGGERAH,NSW,-33.32,151.42,104.72.70.95
+DE,STROM,HB,53.08,8.72,194.25.95.225
+US,MOUNTAIRY,NC,36.4840,-80.6333,209.18.41.27
+CN,PO,AH,33.88,115.77,184.50.87.178
+IR,ARA,"",36.20,53.72,217.212.227.31
+AT,PURKERSDORF,"",48.20,16.17,195.145.147.107
+DE,STUHR,NI,53.03,8.75,80.157.170.221
+BA,TESANJ,"",44.61,17.99,46.33.70.216
+IN,AJMER,RJ,26.45,74.63,117.239.189.115
+PL,TOMASZOW,"",52.33,21.02,80.239.149.123
+DE,DOTTERNHAUSEN,BW,48.23,8.80,194.25.95.225
+MY,PENANG,"",5.42,100.33,203.106.85.113
+US,KANKAKEE,IL,41.1223,-87.9467,23.67.60.217
+PS,RAMALLAH,"",31.90,35.20,92.122.189.85
+ID,KETAPANG,"",-6.15,106.80,23.0.162.21
+IN,SECUNDERABAD,AP,17.45,78.50,23.205.118.109
+US,ASTON,PA,39.8645,-75.4349,184.26.44.42
+MY,KOTABHARU,"",4.40,101.08,58.27.124.241
+US,SAINTMICHAEL,MN,45.1957,-93.7002,63.151.29.12
+US,TIFTON,GA,31.4504,-83.5086,72.246.247.30
+US,PHENIXCITY,AL,32.3790,-85.1147,72.246.247.5
+UA,LUGANSK,"",47.37,37.10,80.239.237.231
+US,MALVERN,AR,34.3189,-92.8629,96.16.7.120
+NO,SANDEFJORD,"",59.13,10.23,2.21.240.40
+US,UPPERMARLBORO,MD,38.7800,-76.7676,184.28.17.76
+FR,STIRINGWENDEL,"",49.20,6.93,80.157.150.201
+US,ASHTABULA,OH,41.8515,-80.79,107.14.38.218
+US,MARLTON,NJ,39.8786,-74.8969,184.26.44.42
+DE,LUDWIGSHAFEN,RP,49.48,8.44,2.20.142.173
+DE,BADRA,TH,51.40,10.97,23.14.94.214
+IN,SHIMLA,RJ,28.68,74.57,96.17.182.136
+IR,KHORASAN,"",35.70,47.27,184.25.157.155
+US,GROVELAND,MA,42.7505,-71.0153,184.25.109.213
+US,GRANITEFALLS,NC,35.8300,-81.4147,23.79.240.37
+US,SMITHVILLE,TN,35.9094,-85.7998,23.79.240.36
+US,HOLT,MI,42.6321,-84.5423,23.67.60.222
+US,OCEANA,WV,37.7347,-81.5521,96.6.47.120
+US,NEWBURGH,IN,37.9445,-87.4053,23.63.227.214
+US,FOLKSTON,GA,30.9136,-82.1547,63.216.54.216
+US,ELMER,NJ,39.5646,-75.1874,184.27.45.150
+FR,LEBLANCMESNIL,"",48.93,2.45,2.16.117.190
+RU,CHEBOKSARY,"",56.13,47.25,213.155.156.212
+HK,HOMANTIN,"",22.32,114.18,203.186.47.99
+US,TAUNTON,MA,41.9112,-71.1289,184.25.109.196
+US,BIGBEARCITY,CA,34.2842,-116.9019,23.216.10.78
+LS,MASERU,"",-29.32,27.48,184.27.179.181
+US,ANGIER,NC,35.4757,-78.7203,23.79.240.36
+IN,SHILIGURI,WB,26.72,88.42,96.17.182.130
+UA,SEVASTOPOL,CRIMEA,44.60,33.53,88.221.15.111
+US,BATESVILLE,MS,34.3450,-89.8815,96.17.153.157
+IN,ANANTAPUR,AP,14.68,77.60,23.205.118.109
+US,NEWBRAUNFELS,TX,29.6944,-98.0725,96.17.163.165
+US,KILGORE,TX,32.3769,-94.8692,131.103.137.122
+US,COATESVILLE,PA,39.9700,-75.8325,184.26.44.42
+BD,DIAL,"",24.93,89.08,23.75.23.140
+US,MENTONE,CA,34.1048,-117.051,184.50.26.192
+TH,CHAENG,"",15.55,102.38,92.122.189.85
+NL,HILVERSUM,"",52.23,5.18,95.101.2.112
+US,INGRAM,TX,30.1349,-99.4936,23.215.15.32
+US,PIERRE,SD,44.3693,-100.0402,107.14.38.218
+LT,KALVARIJA,"",54.73,25.28,2.21.240.40
+US,COOKEVILLE,TN,36.1802,-85.4582,23.79.240.37
+US,NORTHMANCHESTER,IN,40.9831,-85.7915,23.74.8.8
+BI,BUJUMBURA,"",-3.38,29.36,23.205.169.195
+FI,SALO,"",60.73,24.18,2.21.240.61
+NZ,HOWICK,"",-36.89,174.92,219.88.186.172
+DE,HERTEN,NW,51.60,7.13,194.25.95.212
+US,LAFOLLETTE,TN,36.3953,-84.1409,23.79.240.37
+IT,BARI,"",41.13,16.85,193.45.15.198
+IR,GHARBI,"",28.94,53.24,23.14.94.228
+KR,SUWON,"",37.28,127.02,184.51.199.132
+US,SOUTHPORT,NC,34.0734,-78.0547,209.18.41.23
+DJ,DJIBOUTI,"",11.60,43.15,95.101.34.109
+US,MANDEVILLE,LA,30.3898,-90.0068,184.28.127.55
+IN,THANE,MH,19.20,72.97,96.17.180.166
+US,CORNELIUS,NC,35.4867,-80.8605,72.246.247.30
+US,LINDENHURST,NY,40.6894,-73.3745,184.26.44.38
+DK,LYNGBY,"",55.77,12.52,23.65.29.106
+US,GRASSVALLEY,CA,39.2183,-120.9247,23.61.195.165
+US,FREDONIA,WI,43.4948,-87.9836,107.14.38.217
+LT,KLAIPEDA,"",55.72,21.12,77.67.27.235
+US,MOUNTAINHOME,ID,43.2609,-115.7811,206.104.149.146
+JP,URAWA,11,35.87,139.65,23.3.104.16
+US,RUSSELL,KS,38.8001,-98.8561,23.215.15.32
+US,SENECA,SC,34.7097,-82.9753,72.246.247.30
+US,WALLER,TX,30.0958,-95.9497,96.17.163.161
+JP,KANAGAWA,07,37.58,139.92,202.229.2.227
+US,BERNE,IN,40.6587,-84.8982,65.113.249.11
+SD,KHARTOUM,"",15.59,32.53,23.212.108.28
+US,FORTPIERCE,FL,27.4538,-80.5447,23.79.240.36
+RO,TARGUMURES,"",46.55,24.57,81.196.26.231
+DE,DILLENBURG,HE,50.73,8.28,95.100.169.105
+FR,EVRY,"",48.63,2.45,2.16.117.200
+GB,WIGAN,EN,53.53,-2.62,184.27.139.24
+DE,WORMS,RP,49.64,8.36,92.122.215.67
+US,BUNA,TX,30.4154,-93.9904,165.254.207.117
+US,NEDERLAND,TX,29.9798,-94.0164,107.14.36.199
+US,KERMAN,CA,36.7225,-120.1318,23.61.195.165
+US,LEVITTOWN,PA,40.1722,-74.822,23.67.242.156
+US,SLIDELL,LA,30.2612,-89.7907,184.28.127.58
+US,WELLSBURG,WV,40.2340,-80.5842,184.27.45.157
+US,WESTON,FL,26.0970,-80.3968,72.246.65.23
+US,DEQUINCY,LA,30.3794,-93.4077,23.5.164.146
+PL,STALOWAWOLA,"",50.57,22.05,80.15.235.156
+TR,ANTALYA,"",36.88,30.70,80.239.222.169
+US,STURGIS,MI,41.8205,-85.4431,23.63.227.214
+JP,OKIDATE,02,40.83,140.73,72.246.184.84
+US,GALLOWAY,OH,39.9347,-83.1992,96.17.9.14
+IL,REHOVOT,"",31.90,34.82,82.102.137.137
+US,ARNOLD,MO,38.4305,-90.3985,96.17.14.15
+US,COLVILLE,WA,48.6776,-117.7361,206.104.149.146
+CZ,MILICIN,"",49.57,14.67,92.122.215.89
+US,KRUM,TX,33.2811,-97.313,23.5.164.146
+US,BREA,CA,33.9296,-117.8713,23.61.195.163
+BG,HASKOVO,"",41.93,25.55,93.186.137.228
+FR,DREUX,"",48.73,1.37,2.16.117.200
+JP,TOYONAKA,27,34.78,135.47,23.3.104.20
+US,HERMITAGE,TN,36.1840,-86.6033,23.212.53.75
+US,SELLERSBURG,IN,38.3931,-85.7713,107.14.38.218
+AR,MENDOZA,"",-32.88,-68.82,190.98.167.230
+CN,XINGFA,ZJ,28.44,120.46,72.246.191.16
+US,SHERMAN,TX,33.6449,-96.5899,23.215.15.9
+ID,KALIMANTAN,"",1.62,109.18,96.17.180.177
+US,ADAIRSVILLE,GA,34.3646,-84.9223,72.246.247.5
+RE,REUNION,"",-21.07,55.27,2.20.243.42
+CN,LANGFANG,HE,39.52,116.70,184.84.239.186
+US,BURLEY,ID,42.5011,-113.8145,67.131.104.14
+US,OAKLAWN,IL,41.7129,-87.7521,23.67.60.223
+US,MARTINSBURG,WV,39.4645,-77.9544,184.27.45.150
+PL,TYLAWA,"",49.47,21.70,77.67.96.116
+US,CAMPHILL,PA,40.2398,-76.9205,23.192.161.16
+US,DEERFIELD,MA,42.5381,-72.6067,184.25.109.201
+GB,PRESTON,EN,51.57,-0.30,184.27.139.24
+MY,MELAKA,"",2.20,102.25,58.27.124.248
+US,KLAMATHFALLS,OR,42.2527,-121.8343,184.27.179.159
+US,STEAMBOATSPRINGS,CO,40.4850,-106.8312,184.84.180.101
+US,NEENAH,WI,44.1857,-88.529,107.14.38.218
+US,FLOWERYBRANCH,GA,34.1717,-83.8975,72.246.247.5
+US,ESSEX,MD,39.2951,-76.4387,23.192.161.16
+TH,BANGRAK,"",13.73,100.53,80.239.222.167
+US,LORIS,SC,34.0573,-78.931,184.51.35.215
+JP,JOETSU,15,37.10,138.25,210.175.5.177
+US,VOORHEES,NJ,39.8445,-74.9532,23.67.60.220
+MX,NAVOJOA,SON,27.10,-109.43,173.223.52.70
+GB,KINGSTONUPONHULL,EN,53.72,-0.33,173.222.211.203
+US,PIGEONFORGE,TN,35.7901,-83.5658,23.79.240.48
+AT,RIEDIMINNKREIS,"",48.22,13.50,77.67.27.235
+RO,BOTOSANI,"",47.75,26.67,81.196.26.236
+US,CLEVES,OH,39.2102,-84.7493,165.254.207.117
+US,MANHATTAN,KS,39.1124,-96.5124,23.215.15.9
+US,MINOT,ND,48.1414,-101.3873,107.14.38.218
+US,EASTHARTFORD,CT,41.7810,-72.6206,184.27.45.150
+US,NEWSMYRNABEACH,FL,28.9806,-81.0592,23.34.56.147
+US,MARINGOUIN,LA,30.4461,-91.569,204.93.43.168
+PL,KACZOR,"",50.58,23.15,2.22.52.102
+VN,TANG,"",22.62,104.17,92.122.189.85
+US,GRANDHAVEN,MI,43.0131,-86.1392,23.63.227.227
+FR,AIXENPROVENCE,"",43.53,5.43,2.16.117.200
+US,MONTGOMERYVILLAGE,MD,39.1743,-77.1915,23.192.161.30
+CZ,ZBRASLAV,"",49.97,14.40,92.122.215.67
+US,MANVEL,TX,29.4777,-95.3591,184.28.23.24
+PL,CIS,"",51.28,20.22,2.22.52.105
+US,CLIFTONFORGE,VA,37.8336,-79.7447,184.27.45.157
+US,HASTINGS,MN,44.6820,-92.8732,63.151.29.15
+US,MANTENO,IL,41.2496,-87.8949,184.27.120.65
+MY,JOHORBAHRU,"",1.47,103.75,96.17.180.166
+CA,SUDBURY,ON,46.50,-80.97,67.69.197.92
+TR,ATAKOY,"",38.73,30.55,193.45.15.198
+IR,ZANJAN,"",36.66,48.49,96.17.182.136
+CA,SAINTCATHARINES,ON,43.17,-79.23,72.246.43.215
+US,SHELBY,NC,35.3693,-81.5992,184.27.45.150
+IN,MATHURA,UP,27.50,77.68,124.124.252.160
+US,THEDALLES,OR,45.5517,-121.219,184.27.179.187
+US,RIOGRANDE,NJ,39.0203,-74.8749,184.26.44.38
+SN,MEDINA,"",14.68,-17.45,81.52.201.98
+US,VIRDEN,IL,39.5001,-89.8147,65.113.249.11
+TR,IZMIT,"",40.77,29.92,193.45.15.198
+GR,PATRA,"",38.25,21.73,80.157.169.4
+US,BOGALUSA,LA,30.7419,-89.8828,96.17.153.162
+PL,GOLENIOW,"",53.57,14.82,2.22.52.101
+DE,HAND,NW,50.80,6.05,2.20.142.166
+SB,HONIARA,"",-9.43,159.95,173.197.192.214
+US,ADA,OK,34.7965,-96.7902,23.215.15.22
+CZ,KOLIN,"",50.02,15.20,23.62.237.133
+US,DOWNSVILLE,WI,44.7748,-91.9318,23.74.8.24
+US,ROSEBURG,OR,43.2103,-123.4286,206.104.149.146
+TH,PHUKET,"",7.88,98.40,184.84.180.68
+RO,RAMNICUSARAT,"",45.38,27.05,23.62.237.135
+AT,KLOSTERNEUBURG,"",48.30,16.32,46.33.70.104
+US,OAKCREEK,WI,42.8802,-87.9005,107.14.38.224
+CZ,USTINADLABEM,"",50.67,14.03,23.62.237.135
+JP,WAKAYAMA,30,34.09,135.09,65.116.149.102
+UA,MAKSIM,"",51.20,30.95,92.122.215.67
+FR,BAGNOLET,"",48.87,2.42,2.16.117.190
+US,CHISHOLM,MN,47.5741,-92.8546,23.215.15.32
+US,COTTONDALE,AL,33.1618,-87.3671,192.204.82.239
+US,WILKESBARRE,PA,41.2438,-75.8848,184.25.157.169
+US,FLANDERS,NJ,40.8455,-74.7097,184.26.44.38
+CA,PORTPERRY,ON,44.10,-78.93,72.246.43.215
+RU,VYATKA,"",58.47,35.67,80.239.237.80
+NO,SKI,"",59.72,10.83,2.21.240.40
+IL,JERUSALEM,"",31.77,35.23,96.17.163.165
+MY,LABUAN,"",5.28,115.24,23.15.10.91
+US,HONESDALE,PA,41.6240,-75.2495,184.26.44.38
+US,MAPLESHADE,NJ,39.9516,-74.9946,184.26.44.38
+HK,STANLEY,"",22.22,114.20,96.16.12.216
+US,MAUMELLE,AR,34.8504,-92.3916,96.16.7.101
+DE,NEUBIBERG,BY,48.08,11.68,195.95.193.134
+US,PERTHAMBOY,NJ,40.5225,-74.2746,184.26.44.38
+US,TYRONE,PA,40.6572,-78.2228,184.26.44.38
+US,LILBURN,GA,33.8704,-84.1214,72.246.247.5
+US,KEASBEY,NJ,40.5142,-74.3145,184.26.44.38
+CZ,OPAVA,"",49.95,17.92,23.62.237.137
+MX,VERACRUZ,VER,19.20,-96.13,165.254.1.206
+US,GOOSECREEK,SC,32.9946,-79.999,23.79.240.44
+MY,KOTAKINABALU,"",5.98,116.07,96.17.180.155
+US,WALNUTRIDGE,AR,36.1072,-90.9128,96.16.7.120
+US,SHAMOKIN,PA,40.7842,-76.5797,184.26.44.42
+RO,PETROSANI,"",43.72,25.63,88.221.93.157
+US,OSSEO,MN,45.0992,-93.4917,23.67.60.220
+US,CLEMMONS,NC,36.0036,-80.372,209.18.41.23
+BD,SYLHET,"",24.53,91.87,96.17.180.166
+US,SELAH,WA,46.8035,-120.6744,23.212.59.85
+FR,VILLEPINTE,"",48.97,2.53,217.212.239.109
+US,GADSDEN,AL,34.0512,-85.9648,23.212.53.75
+US,RAILROAD,PA,39.7607,-76.6988,23.192.161.16
+CN,LUOYANG,HA,34.68,112.45,184.50.87.178
+US,LUTZ,FL,28.1415,-82.4686,23.34.56.147
+US,HARRINGTON,DE,38.9242,-75.6177,23.192.161.21
+CN,HUIZHOU,GD,23.08,114.40,184.50.87.178
+VU,LOLTONG,"",-15.55,168.13,88.221.15.111
+US,PORTORCHARD,WA,47.5378,-122.5894,165.254.1.165
+US,HAMDEN,CT,41.3720,-72.9418,184.25.109.213
+US,MENOMONIE,WI,44.8570,-92.0071,184.85.215.165
+US,LAKEINTHEHILLS,IL,42.1832,-88.3453,107.14.38.227
+US,GREENSBURG,IN,39.3206,-85.4768,23.67.60.217
+US,DACULA,GA,33.9712,-83.8738,72.246.247.30
+US,WHITETHORN,CA,40.0707,-124.0094,63.151.119.16
+CN,LANTIAN,GD,23.87,114.22,107.14.44.212
+US,NORWOOD,MA,42.1844,-71.1953,184.25.109.213
+US,MERRITTISLAND,FL,28.2972,-80.6751,23.33.186.134
+US,SUMMERSVILLE,WV,38.3477,-80.8565,184.27.45.150
+US,BROOKINGS,SD,44.3014,-96.8692,23.63.227.227
+CA,CHICOUTIMI,QC,48.43,-71.07,67.69.197.106
+US,DARDANELLE,AR,35.1648,-93.2292,23.79.240.37
+AR,ALVEAR,"",-33.07,-60.62,190.98.167.220
+US,LOMALINDA,CA,34.0484,-117.2603,184.50.26.179
+US,REDOAK,TX,32.5150,-96.8153,96.16.7.120
+US,TOOELE,UT,40.5393,-112.3531,23.215.15.9
+IL,YAKUM,"",32.25,34.85,212.143.162.162
+US,HOCKLEY,TX,30.0437,-95.8249,96.17.163.165
+TR,KONYA,"",37.87,32.52,88.221.93.157
+DE,SOLTAU,NI,52.98,9.83,92.122.207.179
+US,TURTLECREEK,PA,40.4160,-79.8228,72.247.10.237
+US,MASONCITY,IA,43.1451,-93.1385,23.63.227.214
+ID,MENTENG,"",-6.22,106.83,23.0.162.21
+AR,SANMARTIN,"",-34.57,-58.55,23.61.195.149
+US,PORTNECHES,TX,29.9818,-93.9497,184.26.93.116
+US,ERIE,CO,40.0782,-105.0312,184.84.180.98
+US,SWANSBORO,NC,34.7017,-77.1399,209.18.41.23
+RU,BAZA,"",60.60,40.15,2.21.240.40
+US,BLAIRSVILLE,PA,40.4741,-79.2341,23.192.161.16
+SK,KOSICE,"",48.72,21.25,23.62.237.138
+US,BUCYRUS,OH,40.8150,-82.9723,107.14.38.217
+US,WHEELING,IL,42.1311,-87.9211,107.14.38.227
+PR,CAGUAS,"",18.2357,-66.0369,72.246.65.38
+KR,SILLIMDONG,"",37.23,128.08,112.175.42.120
+ES,LINARES,"",40.58,-5.92,92.122.188.163
+US,SKOKIE,IL,42.0355,-87.7304,107.14.38.218
+US,MOUNTCLEMENS,MI,42.5974,-82.8814,69.22.154.219
+US,BEULAVILLE,NC,34.9398,-77.7738,63.151.29.12
+US,RAINBOWCITY,AL,33.9427,-86.0638,23.79.240.36
+FR,BOUGIVAL,"",48.87,2.13,2.16.117.190
+US,HONDO,TX,29.4252,-99.1005,96.17.163.161
+TR,ACI,"",39.73,34.18,80.239.237.231
+US,WESTHAVERSTRAW,NY,41.2083,-73.9777,184.26.44.42
+ID,SOLO,"",-7.58,110.83,23.0.162.21
+GB,WINNERSH,EN,51.42,-0.87,88.221.87.94
+US,SAINTJOHNSBURY,VT,44.4161,-71.9767,63.141.200.241
+IN,AURANGABAD,MH,19.88,75.33,117.239.189.115
+RU,URENGOY,"",65.97,78.37,2.21.240.61
+DE,GELSENKIRCHEN,NW,51.52,7.05,2.20.142.173
+US,EMMETT,ID,43.9488,-116.5537,192.80.13.117
+US,SIDNEY,OH,40.2838,-84.1519,107.14.38.218
+US,CADILLAC,MI,44.2433,-85.5328,23.63.227.214
+US,HOLLIS,NY,40.7171,-73.7686,24.143.199.188
+US,ALVARADO,TX,32.4269,-97.2192,23.5.164.143
+ID,RUNGKUT,"",-7.33,112.77,23.0.162.54
+US,MOKENA,IL,41.5339,-87.885,23.67.60.220
+US,DONORA,PA,40.1785,-79.8649,23.192.161.16
+FR,LORIENT,"",47.75,-3.37,2.16.117.200
+US,WHEATLAND,WY,42.0178,-105.0984,23.212.53.75
+RU,SURGUT,"",53.93,51.23,2.21.240.61
+AT,AMSTETTEN,"",48.12,14.87,23.14.94.224
+RU,VSI,"",60.05,32.38,80.239.237.93
+US,JORDAN,MN,44.6530,-93.5873,23.67.60.222
+US,GRANGER,IN,41.7389,-86.1232,23.67.60.220
+UA,SUDAK,CRIMEA,44.85,34.97,92.122.189.85
+US,LINCOLNSHIRE,IL,42.1941,-87.9317,23.67.60.217
+US,RIVERHEAD,NY,40.9530,-72.642,184.26.44.40
+TR,CANAKKALE,"",40.15,26.40,80.239.237.230
+US,CRAWFORDVILLE,FL,30.1758,-84.3754,184.84.180.98
+FM,POHNPEI,"",8.0001,147.0001,96.17.70.93
+US,TEAGUE,TX,31.6463,-96.2786,184.28.23.24
+US,CANONSBURG,PA,40.2740,-80.1538,184.27.45.162
+US,SOLON,OH,41.3834,-81.4439,107.14.38.224
+US,FREDERICKSBURG,VA,38.2993,-77.4869,96.6.47.120
+US,FOXLAKE,IL,42.3951,-88.1755,23.67.60.222
+IR,ESFAHAN,"",32.66,51.67,96.17.182.136
+US,WHITEWATER,WI,42.8048,-88.7446,184.85.215.170
+US,HARRISONVILLE,MO,38.6236,-94.3109,205.185.195.170
+AT,SCHWAZ,"",47.33,11.70,46.33.70.97
+DK,RY,"",56.08,9.77,95.101.2.122
+US,STAUNTON,VA,38.1221,-79.0825,184.26.44.42
+US,HUGHSON,CA,37.5927,-120.8607,23.216.10.54
+IN,MOHALI,PB,30.78,76.69,23.211.135.66
+US,CALHOUN,GA,34.4962,-84.9097,72.246.247.5
+US,CHILDRESS,TX,34.4383,-100.1979,23.5.164.146
+US,BELOIT,WI,42.5474,-89.1358,184.85.215.165
+US,PORTTOWNSEND,WA,48.0260,-122.8596,24.244.17.205
+KZ,BALKHASH,"",46.67,79.33,217.212.227.25
+CA,SAINTETHERESE,QC,45.63,-73.85,67.69.197.95
+US,FINDLAY,OH,41.0444,-83.65,209.18.41.27
+US,IMPERIAL,MO,38.3874,-90.4319,96.17.14.16
+FR,CACHAN,"",48.78,2.33,2.16.117.190
+US,MORAGA,CA,37.8315,-122.1123,23.61.195.163
+US,NEWBERLIN,WI,42.9726,-88.1602,23.63.227.214
+IN,JHANSI,UP,25.43,78.58,96.17.182.136
+US,DEERFIELDBEACH,FL,26.3109,-80.1005,23.79.240.36
+US,GOLDEN,CO,39.7164,-105.2437,63.235.21.141
+US,WESTMONROE,LA,32.5473,-92.2007,184.84.180.92
+US,TIFFIN,OH,41.1540,-83.2212,184.27.45.150
+CZ,BENESOV,"",49.78,14.68,23.62.237.135
+IN,TIRUCHENGODU,TN,11.38,77.93,117.239.240.76
+CA,WELLAND,ON,42.98,-79.25,72.246.43.237
+US,GREENBELT,MD,39.0047,-76.8758,23.192.161.21
+IR,SHIRAZ,"",29.61,52.54,96.17.182.136
+SG,WOODLANDS,"",1.44,103.78,23.5.165.168
+AU,MOUNTWAVERLEY,VIC,-37.88,145.13,184.84.238.30
+GB,SHEFFIELD,EN,53.37,-1.50,173.222.211.190
+US,INDIALANTIC,FL,28.1099,-80.5786,23.33.186.134
+US,MORRISPLAINS,NJ,40.8475,-74.4826,184.26.44.42
+US,TILLAMOOK,OR,45.4813,-123.6742,184.27.179.165
+US,LUDINGTON,MI,43.9737,-86.4001,23.63.227.227
+US,NORTHBROOK,IL,42.1255,-87.8406,165.254.207.111
+AU,CEDUNA,SA,-32.12,133.67,23.205.117.4
+IT,PISA,"",43.72,10.38,2.18.240.95
+CN,QUZHOU,ZJ,28.97,118.87,72.246.191.19
+US,PERHAM,MN,46.6280,-95.6018,198.63.196.223
+US,BRADY,TX,31.0630,-99.3372,23.215.15.9
+US,BENSALEM,PA,40.1068,-74.9379,184.27.45.157
+US,MONTOURSVILLE,PA,41.2816,-76.8857,23.67.242.139
+US,HODGENVILLE,KY,37.5720,-85.7077,23.79.240.36
+US,BRYSONCITY,NC,35.5051,-83.603,96.6.47.106
+FI,RAAHE,"",64.68,24.48,46.33.64.237
+US,SAINTAUGUSTINE,FL,29.8475,-81.2787,80.239.237.231
+AF,ENAW,"",37.02,70.13,23.212.108.28
+US,GRAYSON,GA,33.8909,-83.9601,72.246.247.5
+CN,DEQING,ZJ,30.55,120.08,117.103.188.218
+BR,AMERICANA,SP,-22.74,-47.33,201.6.5.13
+US,CARTERSVILLE,GA,34.1498,-84.8279,23.79.240.36
+CN,XIANGTAN,HN,27.85,112.90,184.50.87.178
+JP,TOTTORI,31,35.50,134.23,117.104.139.162
+US,BELLEVIEW,FL,29.0589,-82.0588,23.34.56.142
+DE,ETTLINGEN,BW,48.95,8.40,92.122.207.164
+US,CREEDMOOR,NC,36.1139,-78.6265,184.27.45.150
+MQ,FORTDEFRANCE,"",14.60,-61.08,23.74.2.7
+CZ,TRINEC,"",49.68,18.65,23.62.237.137
+CN,HAIDIAN,BJ,39.98,116.30,184.51.199.145
+US,PAGOSASPRINGS,CO,37.1765,-106.8964,23.212.53.64
+US,STANTON,IA,40.9868,-95.099,65.113.249.8
+US,WAUNAKEE,WI,43.1852,-89.4585,23.63.227.214
+US,DUNDALK,MD,39.2639,-76.497,23.67.242.139
+US,SOUTHINGTON,CT,41.6129,-72.8728,184.28.17.76
+US,EUCLID,OH,41.5709,-81.5266,96.17.9.14
+US,LAKEOSWEGO,OR,45.4082,-122.6837,23.212.59.63
+US,MONTICELLO,IN,40.8005,-86.6926,23.67.60.217
+US,MORROBAY,CA,35.4012,-120.7993,23.216.10.78
+NZ,GREYMOUTH,"",-42.47,171.20,219.88.186.167
+HN,LACEIBA,"",13.80,-87.28,23.74.2.7
+US,PARKHILLS,MO,37.8386,-90.5648,204.93.47.220
+ZA,MIDRAND,"",-25.96,28.14,41.193.163.53
+US,PERU,IL,41.3434,-89.1366,184.27.120.65
+IN,TIRUVANNAMALAI,TN,12.22,79.07,184.25.157.155
+US,ARAB,AL,34.3320,-86.4894,204.2.243.135
+FI,VAASA,"",63.10,21.60,2.21.240.40
+CA,NORTHBATTLEFORD,SK,52.77,-108.28,184.150.187.237
+US,ROSEMOUNT,MN,44.7330,-93.0593,184.85.215.170
+AU,DONCASTER,VIC,-37.78,145.13,60.254.143.219
+NO,HORTEN,"",59.41,10.47,2.21.240.40
+IN,VADODARA,GJ,22.30,73.20,23.57.69.159
+RU,PODOLSK,"",55.43,37.55,2.21.240.61
+US,CANANDAIGUA,NY,42.8488,-77.3077,209.18.41.23
+US,HUTTO,TX,30.5231,-97.5348,63.141.200.241
+US,ROBESONIA,PA,40.3646,-76.1416,184.27.45.157
+US,MANKATO,MN,44.1156,-93.9984,184.85.215.165
+CN,SUZHOU,JS,31.31,120.62,72.246.191.16
+US,ALTAMONTESPRINGS,FL,28.6657,-81.3692,23.34.56.147
+US,LAVEEN,AZ,33.3032,-112.1882,63.226.34.165
+AU,CHELTENHAM,VIC,-37.97,145.05,184.84.238.9
+US,YOUNGSVILLE,LA,30.0840,-92.0053,23.215.15.9
+DE,KAMPLINTFORT,NW,51.50,6.53,92.122.189.85
+US,SANGER,TX,33.3623,-97.2076,23.5.164.146
+US,POST,TX,33.1799,-101.2984,205.185.195.170
+WS,APIA,"",-13.83,-171.73,63.217.8.137
+GB,STOURBRIDGE,EN,52.47,-2.13,195.245.125.107
+JP,MIYAGI,01,43.37,143.80,202.229.2.212
+US,SULPHUR,OK,34.4826,-96.973,107.14.43.30
+BD,MOLLA,"",23.80,90.92,96.17.180.166
+US,PONTEVEDRABEACH,FL,30.2396,-81.3855,184.51.145.7
+AT,HOCHSTRASS,"",48.13,15.97,195.145.147.108
+US,SUNNYSIDE,NY,40.7442,-73.9205,24.143.199.156
+US,CARLJUNCTION,MO,37.2082,-94.5634,209.170.117.178
+JP,FUSSA,13,35.74,139.33,23.15.1.67
+US,WESLACO,TX,26.1701,-97.9943,184.26.93.116
+US,IONIA,MI,43.0186,-85.0515,23.63.227.227
+US,CLIFTONPARK,NY,42.8536,-73.7851,107.14.38.218
+US,FARIBAULT,MN,44.3009,-93.28,23.79.255.153
+GB,WALFORD,EN,51.88,-2.60,23.67.255.106
+US,MERRILL,WI,45.2167,-89.8732,92.122.189.114
+US,MILTON,FL,30.7972,-86.9425,96.17.153.162
+US,MATAWAN,NJ,40.4118,-74.2499,23.67.242.139
+MY,KAMPAR,"",4.30,101.15,203.106.85.113
+CZ,SKUTEC,"",49.85,16.00,23.62.237.135
+DE,HATTINGEN,NW,51.40,7.17,195.145.147.101
+US,VILLARICA,GA,33.7153,-84.9212,23.79.240.37
+US,KENNER,LA,29.9910,-90.2553,96.17.153.157
+US,WESTBURY,NY,40.7560,-73.5739,184.26.44.38
+US,PHARR,TX,26.1569,-98.1914,184.26.93.116
+US,SAINTCLAIRSVILLE,OH,40.0964,-80.9221,23.192.161.21
+KZ,AKMOLA,"",42.67,70.97,80.239.237.80
+AT,TULLN,"",48.33,16.05,46.33.70.97
+CH,BUCHS,"",47.45,8.43,2.16.217.206
+US,FAIRLESSHILLS,PA,40.1749,-74.8541,23.79.240.37
+VC,KINGSTOWN,"",13.13,-61.22,23.74.2.12
+IT,LIMANA,"",46.09,12.14,2.18.240.114
+US,BAKER,LA,30.5884,-91.1684,23.215.15.32
+US,ARCHBALD,PA,41.5069,-75.5327,184.27.45.157
+US,CAMERON,MO,39.6971,-94.2694,209.170.117.178
+PW,PALAU,"",7.5002,134.5003,23.76.205.111
+NZ,TASMAN,"",-41.20,173.05,203.96.118.166
+US,MAYFIELD,KY,36.7237,-88.6867,69.31.132.233
+US,WILLIAMSTOWN,NJ,39.6478,-74.9514,184.26.44.38
+JP,SHOWA,05,39.87,140.08,72.246.191.19
+US,GROVECITY,PA,41.1722,-80.0759,65.121.209.141
+US,BETHELPARK,PA,40.3204,-80.0367,96.6.47.106
+US,MENDENHALL,MS,31.9629,-89.7927,96.17.153.157
+US,GARRETT,IN,41.3275,-85.1414,23.74.8.24
+US,LANDRUM,SC,35.1429,-82.1944,63.216.54.236
+ES,MAQUINAS,"",37.70,-4.12,80.239.237.231
+US,PLANTCITY,FL,27.9421,-82.1345,165.254.205.7
+BR,SAOJOSEDOSCAMPOS,SP,-23.18,-45.88,200.174.107.42
+US,BALACYNWYD,PA,40.0138,-75.23,184.27.45.157
+US,FLOWERMOUND,TX,33.0308,-97.0985,23.215.15.32
+US,OLMSTEDFALLS,OH,41.3740,-81.9211,96.17.9.14
+ID,MOJOKERTO,"",-7.47,112.43,23.0.162.54
+US,HAMMONTON,NJ,39.6370,-74.7602,23.67.60.217
+US,HERMOSABEACH,CA,33.8651,-118.3964,184.50.26.185
+US,VALDEZ,AK,60.9721,-146.4265,184.27.179.159
+AU,MASCOT,NSW,-33.93,151.20,23.62.8.21
+CZ,VITKOVICE,"",50.12,13.30,23.62.237.137
+AU,SOUTHBRISBANE,QLD,-27.48,153.02,23.62.8.25
+US,LOVESPARK,IL,42.3453,-89.0028,23.67.60.220
+RU,SOVETSK,"",53.94,37.63,2.20.142.166
+US,AVONLAKE,OH,41.4945,-82.016,107.14.32.235
+US,LYNDHURST,NJ,40.7971,-74.1109,23.67.60.222
+VI,CHRISTIANSTED,"",17.7488,-64.7039,23.34.56.142
+RO,SUCEAVA,"",47.63,26.25,81.196.26.198
+ID,BALIKPAPAN,"",-1.28,116.83,23.0.162.21
+US,CHRISTIANSBURG,VA,37.1299,-80.4092,96.6.47.120
+IR,AHVAZ,"",31.33,48.69,96.17.182.130
+US,ZACHARY,LA,30.6604,-91.1897,23.215.15.22
+MX,DURANGO,DUR,24.03,-104.67,173.223.52.67
+US,SAVOY,IL,40.0399,-88.2643,69.22.154.219
+AT,LEOBEN,"",47.38,15.10,23.62.237.133
+JP,NAKASHIMA,07,37.08,140.95,184.51.199.132
+US,WAUSEON,OH,41.5765,-84.1519,65.113.249.11
+US,HAMEL,MN,45.0776,-93.5754,23.67.60.220
+TR,VAN,"",38.50,43.38,88.221.93.150
+US,RINGGOLD,GA,34.8973,-85.1353,23.79.240.36
+DE,BIEDENKOPF,HE,50.92,8.53,23.14.94.228
+US,MULLINS,SC,34.1893,-79.2589,209.18.41.27
+AU,GOLDCOAST,QLD,-28.00,153.43,23.209.183.50
+FR,BESANCON,"",47.25,6.03,2.16.117.190
+US,MILLHALL,PA,41.0898,-77.4915,23.192.161.30
+IN,MAMALLAPURAM,TN,12.63,80.17,117.239.240.96
+US,KOKOMO,IN,40.5251,-86.1768,23.74.8.24
+FR,SAINTANDRELESVERGERS,"",48.28,4.05,2.16.117.190
+IT,NOLA,"",40.92,14.55,195.22.200.221
+DE,GARCHING,BY,48.13,12.60,23.14.94.220
+US,GREATBEND,KS,38.3903,-98.8296,23.215.15.9
+US,WESTPOINT,MS,33.6681,-88.7618,23.79.240.36
+US,CHESTER,VA,37.3415,-77.403,184.27.45.150
+DE,HAMM,NW,51.68,7.80,92.122.215.89
+US,LAMBERTVILLE,MI,41.7532,-83.627,23.63.227.214
+NO,ASKER,"",59.83,10.43,213.155.156.206
+US,CHECOTAH,OK,35.4498,-95.4869,174.76.226.117
+CZ,PRELOUC,"",50.03,15.57,23.62.237.135
+NL,ENSCHEDE,"",52.22,6.90,95.101.2.112
+US,MENDOCINO,CA,39.3125,-123.7473,23.61.195.165
+US,EQUALITY,IL,37.6964,-88.3404,205.185.195.170
+FR,MOUANSSARTOUX,"",43.62,6.97,81.52.201.98
+CA,SAINTJOHN,NB,45.27,-66.07,72.246.43.215
+US,NORTHCHARLESTON,SC,32.8537,-79.9839,184.27.45.150
+US,NORTHDARTMOUTH,MA,41.6650,-71.0141,184.29.107.38
+US,ELIZABETHCITY,NC,36.3018,-76.2238,63.151.29.15
+JP,HAKATA,27,34.48,135.43,23.3.74.113
+US,DALEVILLE,VA,37.4044,-79.9221,184.26.44.38
+TR,BUYUKCEKMECE,"",41.03,28.58,77.67.29.116
+JP,KAGAWA,35,34.07,131.03,117.104.139.162
+KR,ULSAN,"",35.54,129.32,125.56.214.169
+US,VESTAL,NY,42.0463,-76.0314,107.14.38.227
+DK,VEJLE,"",55.27,10.32,95.101.2.112
+US,TRIANGLE,VA,38.5576,-77.3506,184.27.45.157
+HK,SHEUNGWAN,"",22.28,114.15,58.27.124.248
+US,LEECHBURG,PA,40.6690,-79.6041,23.192.161.16
+CA,THOMPSON,MB,55.75,-97.87,23.74.8.8
+US,GRAHAM,WA,47.0168,-122.2798,23.212.59.63
+AU,NUNAWADING,VIC,-37.82,145.17,150.101.152.245
+US,DOVERPLAINS,NY,41.7225,-73.5844,184.26.44.38
+HK,TAIPO,"",22.45,114.17,23.76.205.90
+CO,BUCARAMANGA,"",4.98,-74.55,200.14.44.108
+US,BRICK,NJ,40.0399,-74.1255,23.67.242.156
+US,LONOKE,AR,34.7557,-91.9476,165.254.138.165
+UA,IVANOFRANKIVSK,"",48.92,24.71,80.239.222.190
+US,NORTHLITTLEROCK,AR,34.7664,-92.255,173.197.194.159
+CH,LIESTAL,"",47.47,7.73,23.14.94.220
+US,PLAINVIEW,TX,34.1983,-101.7867,23.5.164.146
+MN,KHANUUL,"",48.02,114.67,92.122.215.89
+US,SMITHERS,WV,38.1675,-81.3038,184.28.17.76
+FO,THORSHAVN,"",62.02,-6.77,23.215.60.64
+IN,PUDUCHERRY,PY,11.93,79.83,124.124.252.153
+PL,STARACHOWICE,"",51.07,21.07,80.15.235.163
+US,ISHPEMING,MI,46.4126,-87.6827,65.113.249.11
+AT,THAL,"",48.23,15.40,195.145.147.107
+US,AMESBURY,MA,42.8537,-70.9439,184.25.109.200
+KZ,USTKAMENOGORSK,"",49.98,82.61,2.21.240.40
+US,ALACHUA,FL,29.8204,-82.4896,63.216.54.231
+IN,WARANGAL,AP,18.00,79.58,213.248.108.233
+CH,REGENSDORF,"",47.43,8.47,193.247.167.214
+RU,SEVERSK,"",56.62,84.88,80.239.237.93
+US,BAYVILLE,NJ,39.9119,-74.2096,184.26.44.38
+US,TOWSON,MD,39.4025,-76.6344,23.192.161.16
+US,YORKVILLE,IL,41.5984,-88.4334,23.67.60.222
+US,PURCELL,OK,34.9880,-97.4962,23.5.164.143
+US,COPPERASCOVE,TX,31.2607,-98.1131,107.14.43.29
+FI,JYVASKYLA,"",62.23,25.73,82.96.58.102
+RU,KOSTROMA,"",57.77,40.93,2.21.240.61
+CA,GIMLI,MB,50.63,-97.00,184.27.120.50
+FR,SAINTMAURICE,"",48.82,2.43,2.16.117.190
+TR,BORNOVA,"",38.45,27.23,2.16.153.150
+US,THORNDALE,PA,40.0002,-75.7594,184.26.44.40
+US,ALBION,NE,41.7470,-98.0152,198.173.2.247
+CY,STROVOLOS,"",35.15,33.34,79.140.94.243
+AT,BREGENZ,"",47.50,9.77,195.145.147.107
+CZ,DUKOVANY,"",49.08,16.20,23.62.237.138
+RU,SMOLENSK,"",54.78,32.04,2.21.240.61
+IN,MODASA,GJ,23.47,73.30,117.239.189.110
+US,CONNEAUT,OH,41.8949,-80.5816,204.93.39.36
+US,FORTGEORGEGMEADE,MD,39.0822,-76.7601,23.192.161.21
+US,HOLIDAY,FL,28.1960,-82.7256,23.33.186.101
+CA,DARTMOUTH,NS,44.67,-63.57,67.69.197.95
+US,WESTLIBERTY,KY,37.9370,-83.2694,184.27.45.150
+US,CEDARRAPIDS,IA,41.9747,-91.658,23.79.255.153
+US,WARNERROBINS,GA,32.5887,-83.6576,184.51.35.226
+AE,RASALKHAIMAH,"",25.79,55.94,195.245.125.117
+BR,BAURU,SP,-22.32,-49.07,200.174.107.42
+US,HUBBARD,OH,41.1682,-80.5712,107.14.38.217
+VN,TRUONGDINH,"",9.92,106.13,96.17.180.177
+PL,SLUBICE,"",52.37,19.95,2.22.52.102
+DE,VECHTA,NI,52.72,8.28,195.95.193.132
+FR,VIRYCHATILLON,"",48.67,2.38,2.16.117.200
+US,WESTMILFORD,NJ,41.0879,-74.3771,184.26.44.38
+DE,EMMENDINGEN,BW,48.13,7.85,195.145.147.107
+CA,FERGUS,ON,43.70,-80.37,65.116.149.102
+RS,DOLOVO,"",42.57,20.56,23.14.94.228
+CA,STONEYCREEK,ON,43.22,-79.75,72.246.43.237
+US,GROVETOWN,GA,33.5121,-82.2984,184.27.45.157
+KG,JALALABAD,"",40.93,73.00,80.239.217.231
+US,CRESTVIEW,FL,30.7849,-86.5136,184.27.45.157
+US,BEACHWOOD,OH,41.4698,-81.5121,96.17.9.14
+NP,PALPA,"",27.87,83.48,23.205.118.109
+RO,TIMIS,"",48.03,26.98,80.239.149.123
+PL,LIS,"",51.72,18.12,2.22.52.105
+RU,VOLGODONSK,"",47.51,42.15,213.155.156.206
+US,SOUTHPLAINFIELD,NJ,40.5745,-74.4149,184.28.17.76
+NO,TAFJORD,"",62.25,7.43,82.96.58.85
+TH,DHONBURI,"",13.72,100.48,110.164.11.192
+SI,GORA,"",46.13,14.80,194.25.95.225
+US,BATESBURG,SC,33.9549,-81.564,204.2.243.143
+PH,MONTE,"",18.03,120.52,58.71.107.119
+CR,DESAMPARADOS,"",9.90,-84.07,72.246.65.38
+RO,PLOIESTI,"",44.95,26.02,2.22.52.102
+SK,SLIAC,"",48.62,19.18,23.62.237.138
+US,ULYSSES,KS,37.5622,-101.308,23.215.15.9
+FR,DORDIVES,"",48.15,2.77,72.246.65.26
+US,DUARTE,CA,34.1397,-117.9765,184.50.26.201
+US,HUNTINGTOWN,MD,38.6096,-76.6075,23.192.161.21
+JP,KAWAJIMA,11,36.01,139.48,23.3.104.29
+US,STANFORD,CA,37.4162,-122.1722,23.61.195.165
+HU,KOBANYA,"",47.48,19.17,23.14.94.220
+US,RUPERT,ID,42.6416,-113.6373,67.131.104.6
+RU,SAVVA,"",54.08,43.07,213.155.156.212
+US,HOQUIAM,WA,47.0202,-123.8781,23.212.59.85
+TR,MANISA,"",38.60,27.43,193.45.15.199
+AT,MARIAENZERSDORF,"",48.10,16.28,23.74.24.66
+US,BEECHGROVE,IN,39.7156,-86.0931,23.67.60.223
+US,GLENPOOL,OK,35.9484,-96.0042,23.215.15.22
+SE,RINGON,O,57.72,11.97,2.21.240.61
+RU,CHELIABINSK,"",55.17,61.40,2.21.240.61
+US,NEWBURYPORT,MA,42.8125,-70.9023,184.25.109.200
+US,EDISON,NJ,40.5175,-74.3955,96.17.180.175
+US,HILTONHEADISLAND,SC,32.2161,-80.7525,23.61.195.165
+US,ROCKWOOD,MI,42.0725,-83.2169,23.67.60.222
+CN,MADIAN,HA,34.23,112.58,72.246.191.16
+US,WABASH,IN,40.7414,-85.8426,23.67.60.222
+US,WINSTED,MN,44.9422,-94.0752,23.74.8.24
+HK,SAIKUNG,"",22.38,114.27,184.84.239.186
+US,HILLSVILLE,VA,36.7370,-80.6935,184.29.107.20
+US,HEMPSTEAD,NY,40.7141,-73.6003,23.62.237.133
+US,BARNWELL,SC,33.2109,-81.3471,72.246.247.30
+US,CARENCRO,LA,30.3321,-92.0496,96.17.153.157
+US,GLENBURNIE,MD,39.1605,-76.5823,23.192.161.30
+PL,KIELCE,"",50.83,20.67,80.15.235.163
+US,PARKRIVER,ND,48.4562,-97.7315,63.216.54.231
+US,SORRENTO,FL,28.8172,-81.4964,23.79.240.48
+US,HURRICANE,WV,38.3842,-81.9872,184.28.17.55
+PL,MAJORAT,"",51.20,21.08,2.22.52.105
+US,CHOCOWINITY,NC,35.4436,-77.0766,63.151.29.15
+US,PARAGOULD,AR,36.0612,-90.5641,204.93.47.220
+US,WITTENBERG,WI,44.8179,-89.172,23.63.227.214
+US,CARBONDALE,IL,37.7248,-89.197,23.74.8.24
+KZ,PAVLODAR,"",52.30,76.95,213.155.156.208
+ID,KELAPAGADING,"",-6.17,106.88,23.0.162.21
+AT,TIROL,"",47.70,15.55,195.145.147.101
+US,COTTAGEGROVE,WI,43.0705,-89.1909,184.85.215.165
+US,CANFIELD,OH,41.0050,-80.7708,184.25.157.169
+CL,CONCEPCION,"",-36.83,-73.05,200.91.22.116
+US,BERTHOUD,CO,40.2947,-105.104,23.212.53.64
+US,IRWIN,PA,40.3156,-79.724,23.192.161.16
+DE,REISER,TH,51.25,10.47,195.145.147.108
+NZ,PARNELL,"",-36.87,174.78,184.28.126.7
+CA,HANNA,AB,51.63,-111.92,66.185.88.190
+US,WOODWAY,TX,31.5103,-97.2578,107.14.43.29
+CN,YINCHUAN,NX,38.47,106.27,72.246.191.16
+FR,GOLFEJUAN,"",43.57,7.08,88.221.83.140
+VE,BARQUISIMETO,"",10.07,-69.33,72.246.65.26
+US,HAVRE,MT,48.7104,-109.7919,165.254.207.117
+US,LEAVENWORTH,KS,39.2650,-95.0476,23.77.234.11
+JP,OI,11,35.85,139.52,72.246.191.16
+MT,BKARA,"",35.90,14.46,79.140.94.234
+US,HEBERSPRINGS,AR,35.6262,-92.064,23.5.164.143
+RU,MOSHKOVO,"",53.89,38.71,80.239.237.93
+US,REDLION,PA,39.8974,-76.608,23.192.161.30
+TH,PHITSANULOK,"",16.83,100.25,61.19.12.79
+US,DUFFIELD,VA,36.7086,-82.8103,23.79.240.36
+US,KAUKAUNA,WI,44.3542,-88.2601,107.14.38.224
+US,LAMAR,MO,37.5121,-94.2674,23.212.53.64
+US,WALNUTPORT,PA,40.7653,-75.56,184.26.44.38
+TR,ALAYBEY,"",38.47,27.13,193.45.15.198
+DE,ARNSTADT,TH,50.83,10.95,23.14.94.214
+US,EASTORANGE,NJ,40.7716,-74.2073,184.26.44.38
+BA,GORAZDE,"",43.67,18.98,23.14.94.228
+CH,PRATTELN,"",47.52,7.68,23.14.94.224
+RU,DON,"",52.43,35.16,2.21.240.40
+US,BURKE,VA,38.7935,-77.2718,63.130.161.239
+US,SHOREWOOD,IL,41.5083,-88.2276,23.67.60.220
+US,BETHANY,OK,35.5140,-97.6431,23.215.15.32
+CA,COQUITLAM,BC,49.27,-122.78,24.244.17.205
+EE,RAKVERE,"",59.35,26.36,217.212.227.31
+UA,NOVOTROITSKOE,"",46.95,36.66,80.239.222.169
+US,RIOVISTA,CA,38.2185,-121.7701,23.212.52.79
+US,HAYSVILLE,KS,37.5657,-97.3491,23.215.15.22
+US,MASSILLON,OH,40.8118,-81.4987,205.185.195.183
+SK,PRIEVIDZA,"",48.77,18.63,92.122.215.67
+RO,ROMANA,"",44.20,24.17,80.239.149.123
+US,CEDARCITY,UT,37.7617,-113.2197,23.61.195.150
+US,BAYVILLAGE,OH,41.4853,-81.9318,96.17.9.8
+US,ERWIN,TN,36.0829,-82.4955,23.79.240.48
+NL,TIEL,"",51.88,5.43,92.122.189.114
+DE,ESCHBACH,HE,50.35,8.53,92.122.215.89
+US,OLEAN,NY,42.0970,-78.4026,107.14.38.218
+NL,ALBLASSERDAM,"",51.87,4.67,95.101.2.122
+US,BARNESVILLE,GA,33.0291,-84.1327,72.246.247.30
+US,HAVERHILL,MA,42.7965,-71.0534,2.21.240.61
+US,LEHIGHTON,PA,40.8001,-75.751,165.254.48.155
+FR,FERRETTE,"",47.50,7.32,2.16.117.200
+GD,SAINTGEORGES,"",12.05,-61.75,23.74.2.12
+US,BELLAVISTA,AR,36.4493,-94.2399,23.215.15.9
+GB,LANGLEY,EN,51.98,0.10,88.221.87.94
+FR,SAINTANDREDESEAUX,"",48.37,-2.02,2.16.117.190
+RO,VASLUI,"",46.63,27.73,213.200.109.183
+MX,PACHUCADESOTO,HID,20.12,-98.73,201.144.215.104
+US,SHELTON,CT,41.3059,-73.1393,184.25.109.200
+US,ASHFLAT,AR,36.2067,-91.585,205.185.195.183
+UA,GONCHAROV,"",48.67,25.20,2.22.52.105
+US,BARABOO,WI,43.4869,-89.7322,184.85.215.165
+US,SWEETWATER,TX,32.5104,-100.3053,23.5.164.143
+NO,TRONDHEIM,"",63.42,10.42,2.21.240.40
+US,DOTHAN,AL,31.2035,-85.4998,23.79.240.48
+US,RUTLAND,VT,43.6369,-72.9375,184.25.109.201
+IN,PHAGWARA,PB,31.22,75.77,213.248.108.244
+UA,VINOGRADAR,"",46.67,30.35,2.22.52.105
+FR,BRUNOY,"",48.70,2.50,2.16.117.200
+FR,PERPIGNAN,"",42.68,2.88,2.16.117.190
+US,LANDOLAKES,FL,28.2463,-82.453,23.79.255.149
+MX,ANAHUAC,NLE,27.23,-100.15,187.210.208.101
+US,KEYSTONEHEIGHTS,FL,29.8670,-81.9355,23.79.240.36
+AR,VILLAMARIA,"",-34.90,-60.37,200.123.201.215
+US,HORNELL,NY,42.3231,-77.6478,107.14.38.217
+AU,MULLUMBIMBY,NSW,-28.55,153.50,202.7.177.76
+FR,BRON,"",47.17,-0.12,2.16.117.190
+US,FISHERS,IN,39.9571,-85.9923,23.67.60.220
+US,MASON,OH,39.3540,-84.3079,107.14.38.224
+BR,UBERLANDIA,MG,-18.92,-48.30,200.174.107.42
+US,BEAVERFALLS,PA,40.7641,-80.3864,23.192.161.21
+US,TAYLORSVILLE,NC,35.9243,-81.216,72.246.247.30
+US,DELPHI,IN,40.5373,-86.6356,72.247.10.237
+CK,AVARUA,"",-21.20,-159.77,23.216.10.54
+US,MEXIA,TX,31.6887,-96.511,67.131.44.154
+US,GOFFSTOWN,NH,43.0165,-71.5582,184.25.109.213
+CN,SHAOXING,ZJ,30.00,120.58,117.103.188.205
+US,HARDINSBURG,KY,37.7834,-86.4612,23.220.100.223
+GB,BROMLEY,EN,51.42,0.02,23.67.255.158
+US,GARDENDALE,AL,33.7057,-86.8471,72.246.247.5
+US,SATELLITEBEACH,FL,28.1733,-80.598,23.33.186.101
+CY,LARNACA,"",34.92,33.63,79.140.94.183
+AT,GERASDORF,"",48.28,16.47,46.33.70.97
+US,STOW,OH,41.1788,-81.4432,107.14.38.227
+US,MARSHFIELD,WI,44.6687,-90.1714,184.85.215.165
+US,POOLER,GA,32.1122,-81.2597,23.79.240.36
+PL,WLOCLAWEK,"",52.65,19.03,80.239.222.190
+CA,STEINBACH,MB,49.52,-96.68,184.25.157.155
+US,SPANISHFORK,UT,40.1192,-111.6894,23.215.15.32
+US,LAKECITY,FL,30.1899,-82.6394,23.79.240.48
+AU,BAYSWATER,VIC,-37.85,145.27,23.14.94.224
+TR,BALIKESIR,"",39.65,27.88,2.21.240.61
+US,DERBY,NY,42.6878,-78.9939,184.26.44.40
+FR,TOURS,"",47.38,0.68,2.16.117.190
+JP,IWAKUNI,35,34.15,132.18,184.51.199.145
+FR,DOUAI,"",50.37,3.07,2.16.117.200
+RO,TARGOVISTE,"",44.93,25.45,81.196.26.198
+BG,BALCHIK,"",43.42,28.17,93.186.137.230
+US,PETERSBURG,VA,37.2163,-77.4783,184.27.45.150
+DE,BEILNGRIES,BY,49.04,11.47,2.22.61.102
+CN,LIAOYANG,LN,41.23,123.10,23.5.164.143
+GB,WORTHING,EN,50.80,-0.37,23.67.255.158
+US,BLOOMFIELD,NJ,40.8099,-74.187,23.67.242.139
+US,MAYWOOD,CA,33.9888,-118.1876,184.50.26.194
+US,PELHAM,AL,33.3024,-86.8026,72.246.247.30
+US,STREATOR,IL,41.1182,-88.8294,23.74.8.24
+US,RIORICO,AZ,31.4762,-111.1242,63.226.34.181
+US,UMATILLA,FL,28.9435,-81.6854,63.148.206.235
+PH,CAGAYANDEORO,"",8.48,124.65,202.78.83.170
+US,DEFIANCE,OH,41.3548,-84.3569,107.14.38.227
+EC,AMBATO,"",-1.25,-78.62,23.74.2.12
+US,HARPERWOODS,MI,42.4389,-82.9295,69.22.154.212
+US,NAVARRE,FL,30.5228,-86.8762,96.17.153.157
+PH,MACTAN,"",12.12,123.77,63.217.232.22
+NO,BERGEN,"",60.39,5.32,23.65.29.93
+US,TAFT,CA,35.1546,-119.4343,107.14.43.29
+TR,TEKIRDAG,"",40.98,27.52,193.45.15.199
+US,RAEFORD,NC,35.0278,-79.2454,63.151.29.15
+US,ENNIS,TX,32.3479,-96.579,65.113.249.8
+JP,KASAOKA,33,34.50,133.50,23.3.104.29
+US,SOUTHHAVEN,MI,42.4049,-86.2175,23.67.60.220
+US,HARLINGEN,TX,26.2089,-97.6849,65.113.249.11
+BE,MONS,"",50.45,3.93,23.62.100.154
+US,SALKUM,WA,46.5139,-122.656,165.254.144.25
+RO,SATUMARE,"",46.33,25.37,46.33.70.104
+VN,TANLAP,"",10.92,107.18,96.17.180.155
+IN,MYLAPORE,TN,13.03,80.27,124.124.201.227
+US,PLEASANTGROVE,UT,40.3798,-111.7415,184.84.180.68
+SE,KARLSTAD,S,59.37,13.50,80.239.237.93
+US,CROCKETT,TX,31.2828,-95.4821,23.215.15.9
+US,HARBORCITY,CA,33.7982,-118.3001,184.87.195.109
+US,HIXSON,TN,35.1670,-85.2137,23.79.240.36
+NO,STAVANGER,"",58.97,5.75,217.212.227.25
+US,SANBENITO,TX,26.1784,-97.6678,184.26.93.111
+US,ATLANTICCITY,NJ,39.3648,-74.4342,23.67.242.156
+US,MIDDLEVILLAGE,NY,40.7154,-73.8794,24.143.199.188
+AU,HILLCREST,QLD,-17.37,145.60,23.62.157.32
+US,HURST,TX,32.8164,-97.1774,23.215.15.32
+IN,UDAGAMANDALAM,TN,11.40,76.70,117.239.240.96
+US,DOLTON,IL,41.6290,-87.5979,23.67.60.220
+NZ,WHANGAREI,"",-35.72,174.32,219.88.186.167
+US,FORDS,NJ,40.5421,-74.3112,23.192.161.30
+US,CORTEMADERA,CA,37.9238,-122.5131,216.246.93.44
+AT,SCHLADMING,"",47.38,13.68,46.33.70.104
+ID,SAMBU,"",1.17,103.90,118.98.42.129
+US,STILWELL,OK,35.7926,-94.6204,184.51.101.56
+ZA,MARSHALLTOWN,"",-26.20,28.08,196.37.155.136
+FR,LAGNY,"",49.08,2.75,2.20.243.45
+GB,BECKTON,EN,51.52,0.07,23.67.255.158
+AU,DARWIN,NT,-12.47,130.83,184.86.223.76
+US,PORTISABEL,TX,26.0776,-97.3389,184.26.93.111
+US,RAVENNA,OH,41.1736,-81.1686,107.14.38.227
+IR,QOM,"",34.65,50.88,92.122.215.67
+US,LINCOLNPARK,MI,42.2429,-83.1811,69.22.154.219
+US,SILSBEE,TX,30.3978,-94.1766,107.14.43.30
+US,GALLIPOLIS,OH,38.7997,-82.2553,96.17.9.14
+US,NEWROCHELLE,NY,40.9182,-73.785,23.67.242.156
+US,WILSON,NC,35.7058,-77.9227,209.18.41.23
+US,FARMERVILLE,LA,32.7394,-92.2308,96.17.153.157
+US,BAXTERSPRINGS,KS,37.0595,-94.7764,209.170.117.178
+IR,SHAHRIYAR,"",35.66,51.06,23.57.69.156
+PL,TARNOBRZEG,"",50.58,21.68,80.15.235.161
+US,LYNNHAVEN,FL,30.2384,-85.6449,184.84.180.97
+KR,CHUNGNAM,"",36.27,128.02,125.56.214.169
+ID,SOSIAL,"",-9.49,124.85,23.0.162.40
+US,ROYSECITY,TX,32.9603,-96.3618,23.5.164.143
+IN,RANIPPETTAI,TN,12.93,79.33,117.239.240.96
+US,HARWOOD,MD,38.8654,-76.6145,23.192.161.30
+US,CHICAGOHEIGHTS,IL,41.5054,-87.5907,23.63.227.227
+US,DRAPER,UT,40.5003,-111.8772,184.84.180.98
+US,WOODRIVER,IL,38.8622,-90.0969,204.93.47.216
+US,STRUM,WI,44.5831,-91.3728,23.74.8.8
+JP,OTSUKA,32,35.38,133.27,104.74.70.98
+US,NEWTOWNSQUARE,PA,39.9794,-75.4369,23.74.8.8
+US,GRAYSLAKE,IL,42.3279,-88.0546,107.14.38.224
+US,SMITHTON,MO,38.6141,-93.1156,65.113.249.11
+US,WHITEHALL,MI,43.3852,-86.3162,23.63.227.227
+US,GULFSHORES,AL,30.2490,-87.8145,184.51.35.215
+IR,KAMYARAN,"",34.79,46.94,23.14.94.214
+US,CENTRE,AL,34.0680,-85.5772,23.79.240.36
+JP,KAKEGAWA,22,34.77,138.02,23.3.104.29
+BG,BURGAS,"",42.50,27.47,213.248.108.233
+US,HERCULANEUM,MO,38.2616,-90.3893,96.17.14.15
+FR,PFAFFENHOFFEN,"",48.85,7.62,2.16.117.190
+US,CANDLER,NC,35.5160,-82.718,23.79.240.48
+US,ABITASPRINGS,LA,30.4796,-89.9372,23.215.15.22
+FR,COURBEVOIE,"",48.54,2.15,2.16.117.190
+KR,HANGYANG,"",35.41,127.84,125.56.214.149
+US,MOREHEAD,KY,38.2298,-83.4396,184.51.101.56
+CN,DANJIANGKOU,HB,32.54,111.51,63.233.61.151
+US,MUSKEGO,WI,42.8864,-88.1268,65.113.249.8
+IR,MALAYER,"",34.29,48.82,80.239.149.123
+IN,ANNANAGAR,TN,13.08,80.22,23.205.118.109
+RU,KOMSOMOLSKNAAMURE,"",50.56,137.00,2.21.240.40
+US,BARTOW,FL,27.8693,-81.7818,165.254.205.13
+KN,BASSETERRE,"",17.30,-62.72,184.26.44.38
+RU,SIBIR,"",59.13,48.55,2.21.240.61
+DE,OHL,NW,50.98,7.38,194.25.95.214
+US,LAKESTATION,IN,41.5743,-87.2638,23.67.60.222
+JP,SAKURA,12,35.72,140.23,23.61.250.113
+RO,MEDIAS,"",46.17,24.35,81.196.26.237
+US,NEWTONFALLS,OH,41.1752,-80.9706,107.14.38.218
+US,BRANSON,MO,36.6436,-93.2185,23.5.164.146
+US,LAVERGNE,TN,36.0144,-86.5554,23.212.53.75
+CH,NOIRMONT,"",47.22,6.95,213.254.212.98
+US,WESTBROOK,ME,43.7142,-70.3494,107.14.38.227
+IN,ROORKEE,UL,29.87,77.88,96.17.182.136
+FR,CERGYPONTOISE,"",49.00,2.03,2.20.243.42
+US,SAPULPA,OK,35.9978,-96.1373,23.215.15.9
+LI,VADUZ,"",47.13,9.52,195.27.155.193
+US,THREERIVERS,MI,41.9815,-85.6518,23.67.60.220
+US,MURRAY,KY,36.6180,-88.2562,107.14.38.224
+US,YANKTON,SD,42.8878,-97.454,23.63.227.227
+SE,KARLSKRONA,K,56.17,15.58,23.65.29.106
+CA,NELSON,BC,49.48,-117.28,184.27.179.187
+US,KODAK,TN,35.9712,-83.6158,72.246.247.30
+US,TAYLORS,SC,34.9846,-82.3279,72.246.247.5
+US,ELCERRITO,CA,37.9232,-122.2937,23.212.52.79
+SK,HRKOVCE,"",48.08,18.92,23.62.237.135
+US,GETTYSBURG,PA,39.8288,-77.2253,23.192.161.16
+US,FAIRMONT,WV,39.4675,-80.064,23.192.161.16
+US,BROOKHAVEN,MS,31.5898,-90.4722,165.254.138.175
+US,EVERGREENPARK,IL,41.7213,-87.7012,107.14.38.227
+US,WASHINGTONCOURTHOUSE,OH,39.5227,-83.4503,107.14.38.224
+US,HARTLAND,WI,43.1384,-88.3524,65.113.249.11
+KR,DAEGU,"",35.87,128.60,125.56.214.147
+JP,MIYAZAKI,45,31.90,131.43,23.3.104.15
+CA,CHARLOTTETOWN,PE,46.23,-63.13,23.220.148.122
+US,STANDISH,ME,43.8159,-70.4792,23.61.195.150
+US,LADYLAKE,FL,28.9173,-81.9232,23.79.240.36
+LC,CASTRIES,"",14.00,-61.00,23.33.186.134
+CN,NANTONG,JS,32.03,120.87,184.50.87.178
+US,BREWTON,AL,31.1650,-87.0243,96.17.153.162
+ID,MAKASAR,"",-6.28,106.87,184.27.179.159
+AT,RUM,"",47.28,11.45,195.145.147.108
+US,ORTING,WA,46.9930,-122.097,67.131.104.14
+US,AVONPARK,FL,27.5936,-81.3646,184.27.45.150
+US,MINNETONKA,MN,44.9156,-93.484,23.67.60.222
+US,WINDOM,MN,43.9264,-95.2282,23.63.227.227
+US,NORTHMIAMIBEACH,FL,25.9339,-80.1467,165.254.205.13
+US,VINCENNES,IN,38.6298,-87.5042,23.63.227.214
+US,PAYSON,UT,40.0019,-111.732,184.84.180.98
+SE,JARNA,AB,59.10,17.57,2.21.240.40
+JP,KAMO,12,35.50,140.12,184.51.199.132
+EE,KOHTLAJARVE,"",59.40,27.27,213.155.156.207
+US,CODY,WY,44.5150,-109.5903,23.63.227.223
+PL,TRZESZCZYN,"",53.55,14.52,92.122.189.114
+AU,LISMORE,NSW,-28.80,153.27,104.72.70.95
+BT,THIMPHU,"",27.48,89.60,23.76.205.111
+GB,SWANSEA,WA,51.63,-3.97,88.221.87.112
+RO,COMANESTI,"",44.42,24.13,88.221.93.150
+CA,UCLUELET,BC,48.93,-125.52,24.244.17.197
+FR,VER,"",49.10,2.68,23.200.87.59
+US,CATASAUQUA,PA,40.6570,-75.4675,184.29.107.20
+US,CALIFORNIA,MO,38.6124,-92.5168,23.79.255.153
+FR,TOURNONSURRHONE,"",45.07,4.83,2.16.117.190
+US,NEWKENSINGTON,PA,40.5657,-79.707,23.192.161.30
+MW,LILONGWE,"",-13.98,33.78,41.193.163.45
+US,GREENEVILLE,TN,36.1512,-82.8404,23.79.240.48
+US,CAVECITY,KY,37.1209,-85.9332,65.113.249.11
+JP,YOSIDA,38,33.27,132.55,96.7.251.95
+GF,CAYENNE,"",4.93,-52.33,72.246.65.23
+US,DANBURY,CT,41.3768,-73.4601,23.67.60.220
+CM,DOUALA,"",4.05,9.70,2.16.158.137
+US,PASSAIC,NJ,40.8575,-74.1285,184.26.44.40
+US,ATKINS,IA,41.9918,-91.8933,65.113.249.11
+ES,ACORUNA,"",43.37,-8.38,92.122.189.85
+US,WYANDOTTE,MI,42.1883,-83.1904,69.22.154.215
+US,ANDREWS,TX,32.3051,-102.6378,23.5.164.146
+US,ASPEN,CO,39.1256,-106.7972,184.84.180.68
+TR,FATIH,"",41.02,28.94,217.212.227.25
+US,BRISTOW,VA,38.7380,-77.5569,184.28.17.55
+FR,BRIGNOLES,"",43.40,6.07,2.16.117.190
+US,WESTLINN,OR,45.3523,-122.6694,23.212.59.63
+US,CROFTON,MD,39.0135,-76.6813,23.67.242.139
+FR,ANGERS,"",47.47,-0.55,2.16.117.190
+BO,LAPAZ,"",-16.50,-68.15,200.91.22.116
+AU,TEMPLESTOWELOWER,VIC,-37.77,145.12,23.62.224.33
+US,KELSO,WA,46.1383,-122.7605,23.212.59.63
+PG,WAIGANI,"",-9.43,147.17,23.62.157.32
+US,BRONXVILLE,NY,40.9389,-73.8308,69.31.77.200
+US,NORTHCONWAY,NH,44.0406,-71.0915,107.14.38.217
+US,CATSKILL,NY,42.2274,-73.9283,184.29.107.38
+US,OAKFOREST,IL,41.6061,-87.7549,107.14.38.218
+PL,NOWYTARG,"",53.90,19.20,80.239.255.214
+US,PHILOMATH,OR,44.6158,-123.5018,23.212.59.63
+US,HARROGATE,TN,36.5673,-83.5418,184.25.157.169
+TH,PATTAYA,"",12.93,100.88,61.19.12.79
+US,PORTHUENEME,CA,34.1619,-119.2034,23.216.10.48
+US,DEARBORNHEIGHTS,MI,42.2751,-83.2624,23.67.60.222
+US,OELWEIN,IA,42.7073,-91.8755,184.27.120.50
+US,METTER,GA,32.4031,-82.0735,8.18.43.219
+ES,ARTES,"",41.80,1.95,2.20.44.111
+US,STONYBROOK,NY,40.9035,-73.127,209.170.113.240
+CN,YICHUN,HL,47.70,128.90,184.50.87.178
+TM,ASHGABAT,"",37.95,58.38,117.103.188.218
+FR,SARCELLES,"",49.00,2.38,2.16.117.190
+US,DONNA,TX,26.1405,-98.071,184.26.93.111
+IR,PISHGAMAN,"",37.27,48.44,77.67.27.235
+JP,NARA,29,34.68,135.83,117.104.139.162
+SK,SKALICA,"",48.85,17.23,23.62.237.137
+RO,HUNEDOARA,"",45.75,22.90,81.196.26.236
+US,SEALY,TX,29.7835,-96.2064,96.16.7.120
+US,GREENRIVER,WY,41.9520,-109.6565,63.217.8.168
+US,BAYSPRINGS,MS,31.9429,-89.2,69.31.59.63
+US,SILERCITY,NC,35.7397,-79.4342,184.51.35.226
+IT,PIGNONE,"",44.17,9.72,2.18.240.95
+FR,ILLKIRCHGRAFFENSTADEN,"",48.53,7.72,2.16.117.200
+AT,ORTIMINNKREIS,"",47.90,13.78,195.145.147.109
+RU,ISKRA,"",55.16,36.89,80.239.237.84
+US,LONGWOOD,FL,28.7075,-81.3526,23.34.56.142
+JP,MITANI,36,33.93,134.48,23.3.104.29
+DK,MARIAGER,"",56.65,10.00,23.65.29.106
+US,MOUNTHOLLY,NJ,39.9896,-74.8021,184.26.44.40
+IN,JORHAT,AS,26.75,94.22,124.124.252.165
+DE,APEN,NI,53.22,7.80,92.122.207.164
+PG,LAE,"",-6.73,147.00,23.62.157.32
+US,HINSDALE,NH,42.8109,-72.499,184.25.109.213
+US,DODGEVILLE,WI,42.9917,-90.1451,23.74.8.24
+IT,MILANESE,"",38.20,15.73,193.45.15.198
+DE,HANAU,HE,50.13,8.92,23.14.94.214
+RU,KHANTYMANSIYSK,"",61.00,69.10,80.239.217.238
+US,HAZARD,KY,37.2415,-83.2013,63.216.54.231
+BR,JUIZDEFORA,MG,-21.75,-43.35,184.25.157.155
+US,LYONS,KS,38.3042,-98.1167,23.215.15.9
+TR,ISIK,"",39.02,28.37,2.20.142.173
+RO,FOCSANI,"",45.70,27.18,81.196.26.237
+CZ,HAVEL,"",49.08,14.83,2.20.142.166
+ID,SLIPI,"",-6.20,106.78,23.0.162.21
+US,CEREDO,WV,38.3954,-82.5576,209.48.37.183
+US,ORELAND,PA,40.1145,-75.1853,23.67.242.139
+MX,CUAUTITLAN,MEX,19.67,-99.18,201.144.215.103
+US,TRUMBULL,CT,41.2599,-73.2099,65.113.249.11
+CN,NINGDE,FJ,26.66,119.52,184.50.87.176
+SE,KALMAR,H,56.67,16.37,213.155.156.207
+JP,KAWAGUCHI,11,35.81,139.72,23.3.104.16
+RU,ODIN,"",60.08,55.12,2.21.240.61
+DE,GEISELGASTEIG,BY,48.07,11.55,23.14.94.214
+KR,NAEDONG,"",37.27,126.81,80.239.237.230
+US,GRANDISLAND,NE,40.9005,-98.3297,204.93.47.220
+RU,MAGNITOGORSK,"",53.45,59.07,80.239.237.80
+US,GODFREY,IL,38.9622,-90.2202,96.17.14.31
+US,WEST,TX,31.7636,-97.1357,23.5.164.146
+US,SAGHARBOR,NY,40.9692,-72.306,69.31.77.208
+US,DENVILLE,NJ,40.8897,-74.4855,184.26.44.38
+US,TAKOMAPARK,MD,38.9819,-77.0006,23.192.161.16
+US,COLUMBIACITY,IN,41.1479,-85.4772,65.113.249.8
+CA,NEWMARKET,ON,44.05,-79.45,72.246.43.237
+US,WILLOWGROVE,PA,40.1476,-75.1216,23.192.161.16
+US,KAMRAR,IA,42.3937,-93.7196,23.74.8.8
+US,KENDRICK,ID,46.6455,-116.5458,165.254.144.25
+US,PALMERTON,PA,40.8306,-75.5685,165.254.48.150
+SN,DAKAR,"",14.67,-17.43,213.200.109.173
+US,BONITASPRINGS,FL,26.3319,-81.7522,204.93.43.168
+KR,SAMCHOK,"",37.44,129.17,125.56.214.147
+US,SHINGLESPRINGS,CA,38.6203,-120.9818,23.61.195.165
+KE,MERU,"",0.05,37.65,41.193.163.45
+US,ELKINS,WV,38.9430,-79.8268,96.17.9.14
+JP,WAGO,06,38.32,140.17,23.3.104.16
+IR,POLEFASA,"",29.48,52.64,96.17.182.130
+SE,HANINGE,AB,59.10,18.08,217.212.227.25
+US,YULEE,FL,30.6324,-81.6068,184.51.145.22
+US,ROCHELLE,IL,41.9424,-89.0653,23.67.60.220
+US,CARPENTERSVILLE,IL,42.1252,-88.2633,23.67.60.222
+BD,RAMNA,"",23.73,90.40,23.75.23.135
+US,WILLISTON,FL,29.4056,-82.488,23.74.2.12
+US,HALEYVILLE,AL,34.2053,-87.5643,184.27.45.157
+JP,OBIHIRO,01,42.92,143.20,210.175.5.180
+SE,JONKOPING,F,57.78,14.18,82.96.58.102
+CA,VALDOR,QC,48.12,-77.77,67.69.197.95
+US,ROSLINDALE,MA,42.2845,-71.1256,23.67.244.248
+AR,TUCUMAN,"",-26.82,-65.22,200.123.201.219
+US,MILLERSBURG,OH,40.5444,-81.851,65.113.249.11
+FR,LAGARENNECOLOMBES,"",48.90,2.25,2.16.117.190
+US,HUNKER,PA,40.2070,-79.5798,23.192.161.21
+US,CROWLEY,LA,30.2290,-92.3861,23.215.15.9
+MH,MAJURO,"",7.10,171.38,96.7.251.97
+US,OSWEGO,IL,41.6565,-88.316,184.27.120.50
+KR,INCHON,"",37.45,126.73,125.56.214.147
+US,FAIRLAWN,NJ,40.9359,-74.1174,184.26.44.38
+CA,RICHMONDHILL,ON,43.87,-79.43,72.246.43.237
+DE,MUNCHEN,BY,49.55,11.58,23.14.94.228
+EC,LAGOAGRIO,"",0.08,-76.88,200.110.126.67
+RO,ARAD,"",46.18,21.32,80.239.149.123
+NO,PORSGRUNN,"",59.15,9.67,2.21.240.40
+US,MARATHON,FL,24.7161,-81.0717,23.79.240.48
+US,MOORHEAD,MN,46.9239,-96.7135,165.254.114.164
+JP,MIHARA,34,34.40,133.08,117.104.139.162
+US,ELLIJAY,GA,34.6692,-84.4462,184.28.127.55
+TR,ERZURUM,"",39.92,41.28,193.45.15.198
+US,KEOKUK,IA,40.4274,-91.4507,23.67.60.223
+US,MOUNTWASHINGTON,KY,38.0404,-85.559,63.216.54.236
+KZ,TARAZ,"",42.90,71.37,2.20.142.173
+US,MORRILTON,AR,35.2270,-92.6879,23.79.240.48
+US,CRYSTALLAKE,IL,42.2766,-88.31,23.67.60.223
+US,BEVERLY,MA,42.5685,-70.8619,184.25.109.213
+RU,MAGADAN,"",59.57,150.80,72.246.184.84
+US,BELVIDERE,IL,42.2430,-88.8419,23.67.60.220
+RO,BAIAMARE,"",47.67,23.58,81.196.26.231
+US,BANDON,OR,43.0374,-124.3662,184.27.179.187
+US,COPLAY,PA,40.6874,-75.5488,184.26.44.38
+US,OBERLIN,OH,41.2855,-82.2459,184.27.45.157
+CA,ORILLIA,ON,44.60,-79.42,72.246.43.215
+US,ROMEOVILLE,IL,41.6509,-88.0865,23.67.60.222
+US,LUVERNE,AL,31.6954,-86.2748,184.51.35.215
+GB,STIRLING,SC,56.12,-3.95,88.221.87.94
+US,PRIORLAKE,MN,44.6768,-93.4069,23.212.59.85
+US,PLUMMER,ID,47.3045,-116.8787,184.27.179.159
+FR,MOURS,"",49.13,2.27,2.16.117.190
+UA,BELAYATSERKOV,"",49.78,30.12,92.122.189.114
+DK,FREDERIKSHAVN,"",57.43,10.53,23.65.29.106
+NP,JAWALAKHEL,"",27.67,85.32,23.205.118.109
+US,ROCKSPRINGS,WY,41.6045,-108.9543,23.212.53.75
+CD,LUBUMBASHI,"",-11.67,27.47,23.3.15.22
+HU,KAPUVAR,"",47.60,17.03,80.157.150.192
+US,TEHACHAPI,CA,35.1338,-118.5522,184.26.93.111
+GB,WOKING,EN,51.32,-0.53,23.212.108.28
+IN,SOLAPUR,MH,17.68,75.92,23.205.118.106
+FR,SAINTVALERYENCAUX,"",49.87,0.73,2.16.117.190
+US,JONESTOWN,PA,40.4723,-76.5465,23.192.161.30
+MX,ZAMORADEHIDALGO,MIC,19.98,-102.27,23.215.15.9
+DE,GARMISCHPARTENKIRCHEN,BY,47.50,11.10,2.16.217.211
+US,MCCARR,KY,37.6155,-82.1695,184.27.45.157
+FR,SETE,"",43.40,3.68,88.221.15.111
+US,FARMVILLE,NC,35.5541,-77.5679,72.246.247.30
+US,CORALVILLE,IA,41.7135,-91.6243,205.185.195.170
+GB,CROY,SC,57.52,-4.03,23.67.255.106
+IL,SHEFER,"",32.94,35.43,212.25.69.136
+DE,BILSTEIN,NW,51.10,8.02,194.25.95.219
+US,GLADWIN,MI,44.0805,-84.4824,23.63.227.221
+US,CLANTON,AL,32.8085,-86.6769,72.246.247.30
+CN,KASHI,XJ,39.48,75.97,117.104.139.162
+US,SEMMES,AL,30.7548,-88.2659,96.17.153.162
+US,LAPWAI,ID,46.4250,-116.755,184.27.179.187
+AU,PARRAMATTA,NSW,-33.82,151.00,104.72.70.96
+FR,BLOIS,"",47.58,1.33,2.16.117.190
+CA,LEVIS,QC,46.80,-71.17,67.69.197.106
+US,OLIVEBRANCH,MS,34.9420,-89.5387,23.212.53.75
+US,OAKWOOD,IL,40.1323,-87.8022,23.74.8.8
+IN,BHAVNAGAR,GJ,21.77,72.15,92.122.215.67
+US,BLUEBELL,PA,40.1575,-75.2796,23.67.242.139
+US,LEONARDTOWN,MD,38.2757,-76.6352,208.185.55.117
+US,QUINTON,VA,37.5257,-77.1511,23.220.148.108
+US,LOUISBURG,KS,38.5671,-94.6773,23.215.15.22
+ZA,LOCATION,"",-29.33,21.15,196.37.155.135
+US,MONESSEN,PA,40.1512,-79.882,184.26.44.40
+US,REHOBOTHBEACH,DE,38.7115,-75.1086,23.67.242.139
+KR,MASAN,"",37.95,127.32,61.111.58.222
+PH,INTRAMUROS,"",14.60,120.97,23.76.205.90
+ES,MARCHENA,"",38.18,-2.50,213.248.113.118
+US,GRUNDY,VA,37.3014,-82.1027,184.27.45.162
+US,COSHOCTON,OH,40.2085,-81.7893,96.17.9.14
+US,PEABODY,MA,42.5338,-70.9728,184.25.109.196
+DE,SOLINGEN,NW,51.18,7.08,80.157.150.197
+US,CARMEL,NY,41.4470,-73.7115,184.25.109.200
+BE,VEURNE,"",51.07,2.67,46.33.74.161
+FI,KAUNIAINEN,"",60.22,24.74,193.184.164.237
+US,GRANDLEDGE,MI,42.7448,-84.7632,65.113.249.11
+US,FROSTBURG,MD,39.6524,-78.9473,65.121.209.133
+AU,COLO,NSW,-33.43,150.83,23.62.8.25
+DE,SINDELFINGEN,BW,48.70,9.02,23.14.94.228
+US,BURKBURNETT,TX,34.0937,-98.61,107.14.36.199
+US,MUSTANG,OK,35.3779,-97.7427,23.215.15.9
+US,FRANKLINLAKES,NJ,41.0086,-74.2082,23.67.242.139
+CA,KANATA,ON,45.33,-75.90,67.69.197.95
+US,FRUITLAND,MD,38.3183,-75.6331,23.192.161.16
+JP,MITAKA,13,35.68,139.55,23.3.104.29
+US,HOTCHKISS,CO,38.8373,-107.7837,23.74.8.8
+US,NEWINGTON,CT,41.6870,-72.7308,72.247.10.237
+CZ,KRALUPYNADVLTAVOU,"",50.23,14.32,23.74.24.69
+US,PICAYUNE,MS,30.5854,-89.6932,96.17.153.162
+CN,ZHUHAI,GD,22.28,113.57,184.50.87.178
+NO,TROMSO,"",69.67,18.97,2.21.240.40
+AT,RIEZLERN,"",47.37,10.18,92.122.189.114
+KR,CHONJU,"",35.82,127.15,61.111.58.43
+US,GRANDBLANC,MI,42.9173,-83.6285,65.113.249.11
+BA,LUKAVAC,"",43.68,18.27,2.20.142.166
+FR,MONTROUGE,"",48.82,2.32,2.16.117.200
+GB,PAPWORTH,EN,52.23,-0.12,23.67.255.106
+RU,NOVOKUZNETSK,"",53.75,87.10,2.21.240.40
+US,ELMACERO,CA,38.5361,-121.6397,65.113.249.11
+US,CHINAGROVE,NC,35.5831,-80.6086,209.18.41.27
+US,ANSON,TX,32.7550,-99.9177,23.215.15.9
+US,CUTOFF,LA,29.5615,-90.2815,23.212.53.75
+AT,LEOBERSDORF,"",47.92,16.22,195.145.147.109
+FR,VILLENEUVESAINTGEORGES,"",48.73,2.45,2.16.117.190
+MY,KLIAS,"",5.43,115.63,23.198.99.130
+PY,ASUNCION,"",-25.27,-57.67,177.159.159.51
+DE,LUEDENSCHEID,NW,51.22,7.62,195.95.193.134
+US,WINNER,SD,43.2923,-99.8934,23.63.227.214
+US,COUNCILGROVE,KS,38.6824,-96.5126,23.215.15.22
+RU,KASHIRA,"",54.84,38.17,80.239.222.190
+US,PALOSVERDESPENINSULA,CA,33.7772,-118.3685,184.50.26.194
+US,PILOTPOINT,TX,33.3456,-96.9066,23.5.164.143
+US,TOCCOA,GA,34.5647,-83.3246,204.2.243.135
+US,ALCOA,TN,35.7840,-83.9837,23.79.240.36
+JP,TOCHIGI,09,36.38,139.73,202.239.172.99
+IL,ROSHHAAYIN,"",32.09,34.95,82.102.137.148
+TH,BANGCHAK,"",13.68,100.58,180.180.251.217
+US,BUFFALOVALLEY,TN,36.1821,-85.7574,23.79.240.48
+PK,SUKKUR,"",27.70,68.87,23.5.165.167
+US,KENNETTSQUARE,PA,39.8638,-75.7134,23.62.238.220
+IN,RAJAMPET,AP,17.62,78.08,23.205.118.106
+RU,MEGION,"",61.05,76.10,80.239.237.80
+PT,CALDAS,"",41.53,-8.47,195.22.14.133
+US,JAY,OK,36.4327,-94.7494,23.215.15.9
+CN,QINGDAO,SD,36.08,120.34,117.104.138.235
+US,MORROW,GA,33.5846,-84.3286,23.212.53.74
+IN,DIGBOI,AS,27.38,95.62,96.17.182.136
+TZ,DODOMA,"",-7.28,36.35,196.37.155.134
+TW,HSINCHU,"",24.80,120.97,61.220.62.171
+CN,ZUNYI,GZ,27.69,106.91,72.246.191.16
+FR,BURESSURYVETTE,"",48.70,2.17,2.16.117.190
+US,AMITYVILLE,NY,40.6858,-73.4152,23.67.242.139
+US,WESTFORD,MA,42.5863,-71.4398,165.254.48.142
+CN,DATONG,SX,40.04,113.60,72.246.191.16
+US,HIDALGO,TX,26.0932,-98.2413,63.233.112.199
+US,WESTMEMPHIS,AR,35.1461,-90.1892,23.212.53.75
+FR,NIORT,"",46.32,-0.47,2.16.117.200
+US,EASTLAKE,OH,41.6454,-81.4495,96.17.9.8
+RO,HUSI,"",46.68,28.07,81.196.26.237
+CO,CALI,"",3.45,-76.52,200.14.44.100
+US,PARSONS,KS,37.3363,-95.2625,174.76.226.117
+FR,PLESSISBOUCHARD,"",49.00,2.23,2.20.243.45
+US,BORGER,TX,35.7207,-101.246,96.16.7.120
+US,CHEROKEE,IA,42.7282,-95.5804,165.254.207.111
+US,MONETT,MO,36.9016,-93.938,23.5.164.143
+AU,CROWSNEST,NSW,-33.83,151.20,104.72.70.95
+FR,AUCAMVILLE,"",43.80,1.22,2.16.117.200
+CA,LANCIENNELORETTE,QC,46.78,-71.38,67.69.197.106
+US,CHAPMANVILLE,WV,37.9307,-82.0853,209.48.37.183
+US,GUNTERSVILLE,AL,34.3002,-86.3298,204.2.243.135
+NZ,TORBAY,"",-36.69,174.75,219.88.186.167
+US,FOLEY,AL,30.3794,-87.7151,63.151.29.12
+EC,PUYO,"",-1.47,-77.98,72.164.253.68
+US,LAUGHLIN,NV,35.1676,-114.5723,165.254.144.32
+IT,ALZATE,"",45.57,8.58,95.101.34.109
+US,UHRICHSVILLE,OH,40.3767,-81.2875,107.14.38.217
+LT,ANYKSCIAI,"",55.53,25.10,217.212.227.31
+US,NORTHROYALTON,OH,41.3138,-81.7452,107.14.38.224
+IN,BHILWARA,RJ,25.35,74.63,23.14.94.214
+CZ,KROMERIZ,"",49.30,17.40,23.62.237.137
+IR,AZAD,"",36.53,48.52,96.17.182.130
+GB,TADWORTH,EN,51.28,-0.23,23.212.108.28
+RU,POKROVKA,"",56.27,36.93,96.7.251.95
+CN,HUZHOU,ZJ,30.87,120.10,117.103.188.218
+US,SUMNER,WA,47.2034,-122.2395,67.131.104.6
+US,HOTSPRINGS,SD,43.3460,-103.4837,23.63.227.227
+US,PAHRUMP,NV,36.2552,-116.0393,67.131.104.6
+US,ANOKA,MN,45.2924,-93.4325,23.67.60.222
+US,HOWELL,NJ,40.1478,-74.2133,184.26.44.38
+US,HERMON,NY,44.4225,-75.2101,165.254.35.197
+US,KENAI,AK,60.7681,-150.4457,165.254.1.206
+IR,MASHHAD,"",36.30,59.60,96.17.182.136
+US,ESCANABA,MI,45.7785,-87.1788,184.85.215.165
+US,SCHERTZ,TX,29.5872,-98.2801,184.26.93.116
+FR,LYS,"",47.35,3.60,88.221.15.110
+NO,LARVIK,"",59.07,10.00,2.21.240.61
+DE,BAU,NW,51.15,6.32,194.25.95.212
+US,PIPESTONE,MN,44.0660,-96.3302,23.61.195.163
+ID,PONTIANAK,"",-0.03,109.33,23.0.162.40
+AT,EGG,"",47.52,16.22,46.33.70.97
+DE,MELSUNGEN,HE,51.13,9.55,195.145.147.101
+IT,NOVARA,"",45.47,8.63,195.22.200.240
+US,JAMESTOWN,NY,42.0766,-79.2554,63.216.54.229
+US,JEANNETTE,PA,40.3273,-79.6141,63.216.54.216
+US,STORRSMANSFIELD,CT,41.8004,-72.2476,165.254.202.96
+US,FLEMINGSBURG,KY,38.4360,-83.6931,63.216.54.231
+NO,SKIEN,"",59.20,9.60,2.21.240.61
+US,FLOMATON,AL,31.1088,-87.2802,67.131.104.6
+PL,JAROSLAW,"",50.02,22.68,2.22.52.102
+US,GUERNSEY,WY,42.2368,-104.7818,107.14.32.235
+US,ELY,MN,48.0461,-92.0295,23.63.227.223
+NO,BRUMUNDDAL,"",60.88,10.93,2.21.240.40
+AT,KUFSTEIN,"",47.58,12.17,80.239.237.231
+US,EMERYVILLE,CA,37.8359,-122.2848,23.61.195.166
+US,PALESTINE,TX,31.7706,-95.5987,209.18.41.23
+RU,BUZULUK,"",52.81,40.23,80.239.237.80
+US,MUNISING,MI,46.4479,-86.4779,23.79.255.153
+US,NICHOLASVILLE,KY,37.8809,-84.5734,63.216.54.231
+IE,LIMERICK,"",52.66,-8.62,88.221.222.34
+US,CENTERMORICHES,NY,40.8046,-72.7931,184.26.44.38
+US,HARTFORDCITY,IN,40.4568,-85.3505,23.212.53.64
+US,THEODORE,AL,30.5153,-88.1489,96.17.153.157
+AT,PITTEN,"",47.72,16.18,195.145.147.108
+CZ,HOSTING,"",49.02,15.90,23.62.237.133
+AT,EGGELSBERG,"",48.08,13.00,195.145.147.108
+TW,KAOHSIUNG,"",22.63,120.28,61.220.62.175
+US,SEQUIM,WA,48.0015,-123.0905,184.27.179.181
+US,SIOUXCENTER,IA,43.0841,-96.2145,205.185.195.183
+US,SOUTHPORTLAND,ME,43.6292,-70.2915,107.14.38.218
+SE,NORSJO,X,61.72,16.30,80.239.217.238
+US,INDIANORCHARD,MA,42.1526,-72.5046,184.25.109.200
+US,HAZLEHURST,GA,31.8468,-82.5686,72.246.247.5
+US,NAVASOTA,TX,30.3670,-96.0045,23.212.53.64
+US,AMORY,MS,33.9755,-88.4422,23.220.100.223
+AR,LAPLATA,"",-34.93,-57.95,190.98.167.230
+CZ,NOVAVES,"",50.22,14.53,23.62.237.138
+PL,BOLESLAWIEC,"",51.20,18.20,2.22.52.105
+CA,LLOYDMINSTER,SK,53.28,-110.00,184.150.187.241
+FR,VALENCE,"",44.93,4.90,81.52.201.83
+DE,HOLZMINDEN,NI,51.82,9.45,195.95.193.150
+US,PUNTAGORDA,FL,26.9089,-82.0431,23.79.240.48
+MY,SERDANG,"",3.03,101.72,23.15.10.112
+PH,MUNTINLUPA,"",14.38,121.05,63.217.232.22
+MK,STRUMICA,"",41.44,22.64,23.74.24.66
+HU,SZOMBATHELY,"",47.23,16.62,80.157.150.169
+US,LONSDALE,MN,44.4527,-93.4244,23.63.227.227
+FI,HALLI,"",61.87,24.83,80.239.237.93
+DE,UNTERWELLENBORN,TH,50.65,11.43,92.122.215.89
+UA,SEVERODONETSK,"",48.95,38.50,213.155.156.207
+DE,TAXIS,BW,48.70,10.37,80.157.170.154
+US,WHARTON,TX,29.2926,-96.034,96.16.7.101
+US,LATROBE,PA,40.2834,-79.4033,23.192.161.21
+US,COLOMA,MI,42.2090,-86.3279,184.27.120.50
+CA,PRINCEALBERT,SK,53.20,-105.75,184.150.187.237
+US,FALLON,NV,39.5809,-118.3335,209.116.151.185
+CN,FENGTAI,BJ,39.84,116.29,184.51.199.145
+GB,CIRENCESTER,EN,51.73,-1.98,23.67.71.131
+RO,NASAUD,"",47.28,24.40,77.67.27.250
+RU,KOMBINAT,"",50.83,37.82,80.239.222.169
+CR,CARTAGO,"",9.87,-83.92,72.164.253.68
+US,ELMCITY,NC,35.8063,-77.8487,209.170.113.123
+IN,BENGALURU,KA,12.98,77.58,96.17.182.136
+SA,RADWA,"",26.72,50.08,79.140.94.254
+TH,NONTHABURI,"",13.83,100.48,110.164.253.209
+AR,CALETAOLIVIA,"",-46.43,-67.53,190.98.167.230
+US,TUSKEGEE,AL,32.4242,-85.6518,23.63.227.214
+US,PRESCOTTVALLEY,AZ,34.6100,-112.3153,63.226.34.173
+US,CLEBURNE,TX,32.2789,-97.4607,96.16.7.101
+US,KING,NC,36.3197,-80.3548,209.18.41.23
+JP,ISHIKAWA,07,37.15,140.45,23.61.250.113
+US,DIMMITT,TX,34.5255,-102.2563,23.74.8.24
+RU,CHEKHOV,"",55.15,37.48,2.22.52.101
+UA,VOZNESENSK,"",47.70,31.45,2.20.142.173
+JP,IWAKI,07,37.05,140.88,72.246.184.84
+US,HARLAN,IA,41.6064,-95.2684,63.216.54.231
+US,GLENDALEHEIGHTS,IL,41.9203,-88.081,23.74.8.8
+CN,LHASA,XZ,29.65,91.10,184.84.239.186
+HK,TSIMSHATSUI,"",22.30,114.17,23.76.205.111
+FR,LEROURET,"",43.68,7.02,63.80.12.205
+US,DUNDEE,IL,42.1081,-88.3234,107.14.38.218
+IN,VIZIANAGARAM,AP,18.12,83.42,117.239.240.76
+US,FENTON,MO,38.5035,-90.4616,96.17.14.31
+US,FORTPAYNE,AL,34.4140,-85.7188,23.220.100.223
+SE,ORE,AC,63.55,19.68,2.21.240.40
+AU,PYMBLE,NSW,-33.75,151.15,104.72.70.96
+DE,WEIMAR,HE,51.37,9.40,195.95.193.132
+IN,NAHAN,HP,30.55,77.30,2.21.240.61
+US,NASHOTAH,WI,43.1042,-88.4078,107.14.38.224
+IL,NIRIM,"",31.33,34.40,212.25.69.145
+US,LEXINGTONPARK,MD,38.2267,-76.4333,184.27.45.150
+US,WORTHINGTON,MN,43.6980,-95.6043,23.63.227.227
+IR,SEMNAN,"",35.58,53.39,80.239.149.123
+US,MECHANICSVILLE,VA,37.6340,-77.2585,23.79.240.36
+CZ,PRESTICE,"",49.57,13.32,23.62.237.137
+CA,SALABERRYDEVALLEYFIELD,QC,45.25,-74.13,67.69.197.92
+US,TOMSRIVER,NJ,39.9821,-74.1609,23.67.242.156
+US,EFFINGHAM,IL,39.1183,-88.6059,23.67.60.223
+US,ELKINSPARK,PA,40.0732,-75.1248,184.26.44.38
+US,NEWBRITAIN,CT,41.6612,-72.7801,184.25.109.200
+RO,DOROHOI,"",47.95,26.40,88.221.93.150
+US,UKIAH,CA,39.1539,-123.258,23.212.52.93
+US,ELMIRA,NY,42.1046,-76.758,107.14.38.218
+US,MEBANE,NC,36.1105,-79.2671,209.170.113.124
+US,CANTONMENT,FL,30.6195,-87.3241,96.17.153.162
+RO,DEJ,"",47.15,23.87,88.221.93.150
+PH,NAGA,"",12.53,122.10,80.239.237.230
+DE,LUDWIGSBURG,BW,48.90,9.18,84.53.175.90
+US,LOGANTON,PA,41.0290,-77.3175,165.254.35.197
+JP,TOYAMA,16,36.68,137.22,65.116.149.102
+US,COCHRAN,GA,32.4223,-83.3103,23.79.240.36
+US,GOTHENBURG,NE,40.9862,-100.1215,184.85.215.165
+PL,DABROWAGORNICZA,"",50.33,19.20,2.22.52.101
+DE,WALLDORF,HE,50.00,8.58,23.14.94.228
+US,PONCACITY,OK,36.7012,-97.1444,184.28.23.24
+CZ,USTINADORLICI,"",49.98,16.40,23.62.237.133
+US,SEBRING,FL,27.5025,-81.4505,184.51.207.83
+JP,IWAMIZAWA,01,43.20,141.77,23.3.74.113
+US,LEMARS,IA,42.8179,-96.1854,65.113.249.11
+US,KOSCIUSKO,MS,33.0153,-89.5142,165.254.138.175
+ID,SLEMAN,"",-6.47,108.30,23.0.162.21
+PH,CLARK,"",15.21,120.58,23.76.205.90
+US,MARLBOROUGH,MA,42.3495,-71.5482,23.220.148.122
+BR,CAXIASDOSUL,RS,-29.17,-51.18,177.159.174.7
+US,COMMERCECITY,CO,39.8641,-104.8219,184.84.180.98
+PL,WOJCIECH,"",53.87,23.08,2.22.52.105
+US,PLATTSMOUTH,NE,40.9697,-95.9883,184.85.215.165
+AT,HORN,"",48.65,15.65,195.145.147.108
+US,DUNN,NC,35.3234,-78.6207,24.143.197.207
+IT,AVELLINO,"",40.90,14.78,195.22.200.221
+US,FAIRPORT,NY,43.0902,-77.4171,107.14.38.217
+US,BLUEFIELD,VA,37.2441,-81.3675,209.48.37.183
+US,GULFBREEZE,FL,30.3906,-87.0518,96.17.153.157
+AU,BALLARAT,VIC,-37.57,143.85,202.7.177.87
+NL,PUTTE,"",51.37,4.38,92.122.189.85
+PL,IZABELA,"",52.20,21.30,23.14.94.224
+DE,EISENBERG,TH,50.97,11.90,92.122.207.164
+US,VINITA,OK,36.6347,-95.0928,23.212.53.75
+US,MOHEGANLAKE,NY,41.3106,-73.8477,184.26.44.38
+JP,KUNITACHI,13,35.68,139.44,96.7.251.95
+CA,PICKERING,ON,43.87,-79.03,72.246.43.215
+US,FORTATKINSON,WI,42.8930,-88.808,165.254.207.111
+US,GREENBRIER,TN,36.4312,-86.8077,23.79.240.37
+EE,NARVA,"",59.38,28.19,217.212.227.25
+PG,PORTMORESBY,"",-9.48,147.18,23.62.157.31
+US,HEREFORD,TX,34.9614,-102.6133,96.16.7.120
+US,EMPORIA,KS,38.5525,-96.1732,23.215.15.32
+RO,CORABIA,"",43.78,24.50,2.22.52.102
+ZA,WYNBERG,"",-26.10,28.08,95.101.2.113
+US,EASTHAMPTON,NY,40.9893,-72.1859,184.26.44.38
+SK,PIESTANY,"",48.60,17.83,23.14.94.224
+BF,OUAGADOUGOU,"",12.37,-1.52,184.27.45.157
+GB,FARNBOROUGH,EN,51.27,-0.73,184.27.45.150
+US,EXCELSIORSPRINGS,MO,39.3039,-94.2206,23.67.60.223
+DZ,BECHAR,"",31.62,-2.22,90.84.53.194
+ES,VALDECILLA,"",43.38,-3.73,2.20.44.111
+US,MANITOWOC,WI,44.0987,-87.7276,184.28.17.55
+AU,THORNLEIGH,NSW,-33.73,151.08,23.62.8.25
+US,OJAI,CA,34.5795,-119.1248,184.50.26.201
+AT,SIEZENHEIM,"",47.80,12.98,46.33.70.104
+AR,ALBERTI,"",-35.03,-60.27,200.123.201.219
+US,HIAWATHA,IA,42.0568,-91.6844,23.63.227.227
+PL,RODOWO,"",53.47,20.30,2.22.52.109
+DZ,CHLEF,"",36.16,1.33,90.84.53.224
+US,NEWPHILADELPHIA,OH,40.5013,-81.3604,107.14.38.217
+US,GASCITY,IN,40.4885,-85.6017,184.27.45.157
+DE,BRANDERBISDORF,SN,50.87,13.33,92.122.207.164
+RE,SAINTPIERRE,"",-21.32,55.48,23.15.10.106
+US,POLSON,MT,47.7086,-114.2472,23.212.53.64
+US,GRIFFIN,GA,33.2865,-84.3197,72.246.247.30
+US,SODASPRINGS,ID,42.7567,-111.4702,173.223.52.70
+US,ALPENA,MI,45.1042,-83.4937,23.74.8.24
+FI,PIETARSAARI,"",63.65,22.68,193.184.164.238
+US,HAZELWOOD,MO,38.7849,-90.3852,204.93.47.216
+BR,CAMPOGRANDE,MS,-20.45,-54.62,189.72.175.117
+US,KINGSVILLE,TX,27.4762,-97.7965,107.14.43.29
+US,LAVERNIA,TX,29.3560,-98.0927,23.215.15.22
+NO,KOLBOTN,"",59.81,10.80,2.21.240.40
+US,GRAYLING,MI,44.6717,-84.6485,23.79.255.153
+IL,RAMATGAN,"",32.08,34.81,2.18.243.1
+PH,BALABAG,"",11.98,121.92,184.84.239.186
+US,VERNONROCKVILLE,CT,41.8370,-72.4608,184.25.109.213
+US,GRANITEVILLE,SC,33.5725,-81.8284,204.2.243.132
+RU,TULA,"",54.20,37.61,80.239.217.231
+US,OKANOGAN,WA,48.3263,-119.6832,184.27.179.159
+US,TOWNSEND,TN,35.6244,-83.7794,23.79.240.37
+SE,UMEA,AC,63.83,20.25,2.21.240.40
+US,DERIDDER,LA,30.7742,-93.2493,23.5.164.143
+RU,KURGAN,"",53.71,37.10,2.22.52.105
+CH,LOCARNO,"",46.17,8.80,193.247.167.214
+US,GATLINBURG,TN,35.6579,-83.52,23.79.240.36
+US,ELLENWOOD,GA,33.6382,-84.2654,72.246.247.5
+CZ,CHOCEN,"",50.00,16.23,23.62.237.133
+IT,VICENZA,"",45.55,11.55,193.45.15.198
+CZ,CHOMUTOV,"",50.45,13.43,23.62.237.137
+US,ATOKA,TN,35.4184,-89.8065,184.51.147.33
+US,HAZLETON,PA,40.9531,-76.0034,165.254.48.154
+IN,ANDHERI,MH,19.12,72.83,23.211.135.66
+NZ,ROTORUA,"",-38.13,176.25,219.88.186.165
+US,CHIEFLAND,FL,29.4076,-82.903,184.51.145.7
+IR,RAMIN,"",35.58,51.06,165.254.48.155
+ZA,BRYANSTON,"",-26.05,28.03,41.193.163.53
+US,YADKINVILLE,NC,36.1267,-80.6582,184.51.35.226
+IN,RAMACHANDRAPURAM,AP,16.85,82.02,117.239.240.96
+CN,LISHUI,ZJ,28.45,119.90,204.2.166.220
+US,JAMAICAPLAIN,MA,42.3076,-71.1131,23.192.161.30
+US,WHITELAND,IN,39.5510,-86.0995,23.63.227.214
+US,NIAGARAFALLS,NY,43.0967,-79.0337,65.113.249.8
+DE,BADLAER,NI,52.10,8.08,92.122.207.164
+US,HORSHAM,PA,40.1879,-75.1531,23.67.242.139
+MY,BANDAR,"",2.87,101.43,23.198.99.130
+US,PINECITY,MN,45.8356,-92.9649,107.14.38.217
+RU,SARANSK,"",54.18,45.18,2.21.240.61
+US,KINGSBURG,CA,36.4785,-119.5245,96.17.12.44
+US,CATOOSA,OK,36.1721,-95.6946,23.5.164.143
+US,SPEARFISH,SD,44.4638,-103.897,107.14.38.227
+BD,CHITTAGONG,"",22.33,91.83,203.106.85.4
+KR,HWAGOK,"",37.42,127.73,61.111.58.229
+CH,FRAUENFELD,"",47.55,8.90,23.14.94.224
+US,BELMONT,NC,35.2342,-81.041,209.18.41.23
+AU,CAMBERWELL,VIC,-37.83,145.07,104.72.70.96
+CH,NIDAU,"",47.12,7.23,63.216.54.236
+US,KENDALLVILLE,IN,41.4608,-85.2531,65.113.249.11
+DE,SACHSEN,BY,49.30,10.40,213.200.109.183
+NZ,CROMWELL,"",-45.04,169.20,219.88.186.172
+US,CALEDONIA,MI,42.7912,-85.5517,23.63.227.214
+US,FISHKILL,NY,41.5306,-73.8899,184.51.125.79
+BY,NOVOPOLOTSK,"",55.53,28.65,217.212.227.25
+FR,ALLEVARD,"",45.40,6.07,2.16.117.200
+CN,XINYI,GD,22.35,110.94,216.206.101.214
+US,ASTORIA,NY,40.7715,-73.926,184.29.107.20
+US,SUSSEX,WI,43.1492,-88.2347,107.14.38.217
+CN,DONGGUAN,GD,23.03,113.73,184.50.87.178
+DE,NAILA,BY,50.32,11.70,23.14.94.224
+US,COCKEYSVILLE,MD,39.4879,-76.6611,23.67.242.156
+TL,DILI,"",-8.56,125.57,23.0.162.46
+GB,GRIMSBY,EN,53.53,-0.05,88.221.87.94
+PH,OLONGAPO,"",14.83,120.28,120.28.5.112
+US,ETNA,CA,41.4264,-123.0415,23.61.195.160
+US,NORTHAUGUSTA,SC,33.4766,-81.8963,23.79.240.36
+IN,MYSORE,KA,12.31,76.65,23.57.69.159
+US,MARCOISLAND,FL,25.9350,-81.6996,23.79.240.37
+US,HOMOSASSASPRINGS,FL,28.8033,-82.5763,23.33.186.134
+ID,AGUNG,"",-2.03,115.48,23.0.162.54
+PH,CUBAO,"",14.62,121.05,58.71.107.116
+US,BETHALTO,IL,38.9045,-90.0089,23.63.227.214
+PH,TAGUIG,"",14.54,121.06,58.71.107.120
+LV,JELGAVA,"",56.65,23.70,80.239.149.123
+RS,AVALA,"",44.43,19.93,2.20.45.104
+KE,KISUMU,"",-0.10,34.75,41.193.163.53
+US,DUMAS,TX,35.8084,-101.9581,23.215.15.22
+FR,MASSY,"",48.73,2.28,2.16.117.190
+US,CONNEAUTLAKE,PA,41.6180,-80.3248,209.48.37.183
+UA,YALTA,CRIMEA,44.50,34.17,23.14.94.224
+US,NEWBERN,NC,35.1731,-76.9871,184.28.17.76
+US,CARMICHAEL,CA,38.6263,-121.3281,184.84.180.68
+DE,KIRCHHEIMBOLANDEN,RP,49.67,8.02,23.14.94.220
+CA,POINTECLAIRE,QC,45.43,-73.75,165.254.35.197
+US,LURAY,VA,38.6496,-78.431,184.29.107.38
+US,ADELANTO,CA,34.6701,-117.539,184.50.26.194
+HR,RIJEKA,"",45.33,15.61,46.33.70.104
+RU,NEFTEYUGANSK,"",61.08,72.70,80.239.237.80
+US,BLACKMOUNTAIN,NC,35.5991,-82.3046,23.79.240.37
+US,NAPOLEONVILLE,LA,29.9154,-91.0326,23.79.240.37
+MX,SAHUAYODEMORELOS,MIC,20.07,-102.72,23.215.15.22
+US,SPRINGBRANCH,TX,29.8719,-98.3904,23.5.164.146
+JP,FUKUI,18,36.07,136.22,65.116.149.89
+US,PORTANGELES,WA,48.0203,-123.478,67.131.104.14
+CA,CLARKSON,ON,43.52,-79.62,72.246.43.215
+US,CAMBRIAHEIGHTS,NY,40.6944,-73.7359,23.215.15.9
+US,WEARE,NH,43.0801,-71.7237,184.29.107.38
+US,AIRWAYHEIGHTS,WA,47.6581,-117.5937,67.131.104.6
+IN,VALSAD,GJ,20.63,72.93,23.211.135.66
+RS,INDJIJA,"",45.05,20.08,23.62.237.133
+US,EASTLAND,TX,32.4120,-98.7997,23.212.53.75
+US,CORBIN,KY,36.9167,-84.1011,23.220.100.223
+US,MORTON,IL,40.6150,-89.4441,184.27.120.65
+DE,ROSENHEIM,BY,47.85,12.13,23.74.24.69
+HU,KAZINCBARCIKA,"",48.25,20.63,80.239.222.169
+FR,MONTREUIL,"",48.87,2.43,2.16.117.190
+US,FALFURRIAS,TX,27.2181,-98.2459,23.215.15.9
+US,HERMISTON,OR,45.8456,-119.2817,67.131.104.6
+US,WINNSBORO,SC,34.4133,-81.1456,204.2.243.143
+BR,MANAUS,AM,-3.11,-60.03,200.174.107.50
+DE,RASTATT,BW,48.85,8.20,2.16.217.206
+US,NORTHLIBERTY,IA,41.7609,-91.6574,96.17.9.8
+US,BROOKSHIRE,TX,29.8217,-95.9894,64.86.135.210
+US,AMBLER,PA,40.1823,-75.2133,184.26.44.40
+DE,GAGGENAU,BW,48.80,8.33,23.14.94.228
+US,CANYON,TX,34.8890,-101.9043,204.2.223.90
+US,ARDEN,NC,35.4582,-82.5975,96.16.12.216
+MV,NAIFARU,"",5.43,73.33,23.75.23.135
+FR,FERRIERESENGATINAIS,"",48.08,2.78,2.16.117.190
+US,CARROLL,IA,42.0800,-94.8598,65.113.249.8
+US,ALLEGAN,MI,42.5755,-85.8473,23.63.227.223
+US,CAMPBELL,CA,37.2798,-121.955,96.17.12.44
+BR,LONDRINA,PR,-23.30,-51.15,92.122.188.161
+SI,LOZ,"",45.73,14.48,2.20.142.166
+IN,MAHALAKSHMI,MH,18.98,72.80,23.57.69.157
+US,TUSCUMBIA,AL,34.6544,-87.6611,72.246.247.5
+AR,LANUS,"",-34.72,-58.41,200.123.201.215
+IN,MADHAPUR,AP,17.44,78.39,96.17.180.166
+AU,INDIGO,VIC,-36.10,146.57,104.72.70.95
+DE,LIPPE,NW,50.72,8.05,194.25.95.212
+US,ELKVIEW,WV,38.4976,-81.4683,184.28.17.76
+CH,CHIASSO,"",45.83,9.03,193.247.167.214
+US,ALVA,OK,36.8367,-98.8022,184.51.35.226
+US,AMERICANCANYON,CA,38.1778,-122.2572,23.212.52.82
+US,QUARTZSITE,AZ,33.6715,-114.2178,23.74.8.8
+AU,SURRYHILLS,NSW,-33.89,151.21,210.11.142.67
+DE,WEINGARTEN,RP,49.26,8.29,77.67.27.235
+PH,LOYOLA,"",8.33,126.33,23.76.205.111
+SK,NITRA,"",48.32,18.08,23.62.237.138
+US,SPRINGBORO,OH,39.5611,-84.22,107.14.38.224
+US,NORTHVERNON,IN,38.9859,-85.6189,23.74.8.8
+MY,KUCHING,"",1.55,110.33,203.106.85.4
+UA,IRSHAVA,"",48.32,23.05,2.22.52.102
+US,CORNELIA,GA,34.5117,-83.5924,184.25.157.169
+FR,LAGARDERE,"",43.83,0.32,90.84.50.108
+US,EBENSBURG,PA,40.4747,-78.7176,23.192.161.16
+KR,SUYUDONG,"",38.25,127.45,92.122.215.89
+AR,GUALEGUAYCHU,"",-33.01,-58.51,190.98.167.230
+HU,MONOR,"",47.35,19.45,88.221.93.150
+IR,ALI,"",31.88,50.00,96.17.182.130
+FR,LEHAVRE,"",49.50,0.13,2.16.117.200
+CA,TRURO,NS,45.37,-63.30,184.29.107.38
+CA,SAINTEFOY,QC,46.78,-71.30,72.246.43.233
+US,HIGHLANDPARK,NJ,40.5001,-74.4284,184.26.44.40
+GB,POPLAR,EN,51.50,-0.02,88.221.87.112
+US,WALKERSVILLE,MD,39.4904,-77.3477,23.192.161.21
+US,DAPHNE,AL,30.6100,-87.861,96.17.153.162
+FR,BOULOGNEBILLANCOURT,"",48.83,2.25,23.14.94.220
+RU,GEORGIEVSK,"",44.15,43.47,92.122.188.161
+PT,AMADORA,"",38.75,-9.23,212.113.165.116
+DE,AMBERG,BY,49.44,11.86,77.67.27.250
+DE,MARKKLEEBERG,SN,51.28,12.40,195.95.193.150
+DE,SANKTINGBERT,SL,49.28,7.12,194.25.95.212
+US,SPOTSYLVANIA,VA,38.1929,-77.6865,23.192.161.21
+CW,WILLEMSTAD,"",12.10,-68.92,72.246.65.26
+SA,DAMMAM,"",26.43,50.11,23.215.60.48
+MY,GENTING,"",5.28,100.38,58.26.185.116
+CO,IBAGUE,"",4.44,-75.23,200.14.44.100
+CA,NEPEAN,ON,45.45,-75.70,72.246.43.237
+DK,ODENSE,"",55.40,10.38,23.65.29.106
+JP,SANO,09,36.32,139.58,23.3.104.29
+FR,FONTENAYSOUSBOIS,"",48.85,2.48,88.221.15.110
+TR,BILGI,"",38.10,43.25,193.45.15.198
+DM,ROSEAU,"",15.30,-61.40,23.74.2.7
+US,COFFEYVILLE,KS,37.0670,-95.5817,23.215.15.32
+US,PALMYRA,VA,37.8582,-78.2803,184.26.44.40
+CZ,CESKALIPA,"",50.68,14.55,23.62.237.133
+US,ROXBORO,NC,36.4264,-78.951,23.79.240.48
+ID,GEDONG,"",-6.22,106.90,23.0.162.46
+US,GEYSERVILLE,CA,38.7422,-122.8612,184.84.180.92
+PL,SZCZECINEK,"",53.72,16.70,80.239.222.190
+US,SUFFERN,NY,41.1483,-74.1189,23.67.242.156
+FR,PAU,"",43.30,-0.37,2.16.117.190
+DE,HOHENHEIM,BW,48.70,9.22,2.20.142.173
+US,EUSTIS,FL,28.8842,-81.4638,23.79.240.48
+US,STEILACOOM,WA,47.1696,-122.5937,23.212.59.85
+US,RIFLE,CO,39.7934,-108.1357,184.84.180.68
+US,BROADVIEW,IL,41.8498,-87.8859,23.67.60.220
+US,BEATRICE,NE,40.2674,-96.7699,165.254.207.111
+US,WINNEMUCCA,NV,41.1353,-118.1862,65.113.249.11
+CN,QINHUANGDAO,HE,39.93,119.59,23.76.205.90
+US,CHINOVALLEY,AZ,34.8245,-112.4595,63.226.34.176
+US,WESTBEND,WI,43.4212,-88.1854,65.113.249.8
+UA,KRASNOARMEYSK,"",47.15,31.03,92.122.215.89
+US,CENTRALCITY,KY,37.3137,-87.1024,23.79.240.36
+FR,PORTDEBOUC,"",43.40,4.98,2.16.117.190
+US,PEARLCITY,HI,21.4205,-157.9279,184.50.26.203
+FR,PERTUIS,"",43.68,5.50,2.16.117.200
+AT,MITTERRETZBACH,"",48.79,15.99,195.145.147.109
+ZA,RANDBURG,"",-26.10,27.98,41.193.163.53
+US,KENNETT,MO,36.2279,-90.0425,96.17.14.16
+US,HOSCHTON,GA,34.0890,-83.7695,63.216.54.231
+BG,TARNOVO,"",43.07,25.65,23.14.94.220
+US,PARKVILLE,MD,39.3955,-76.5329,23.67.242.156
+US,INMAN,SC,35.0511,-82.0561,63.216.54.231
+US,STROUDSBURG,PA,40.9882,-75.2974,23.67.242.156
+HU,BOLY,"",45.97,18.52,81.93.191.127
+US,NORTHVILLE,MI,42.4188,-83.5284,23.67.60.220
+FI,LAPPEENRANTA,"",61.07,28.18,2.21.240.40
+PL,GDYNIA,"",54.50,18.55,2.22.52.105
+US,SHELLEY,ID,43.2015,-111.522,206.104.149.146
+FR,BERSEE,"",50.48,3.15,2.16.117.200
+US,HOOPESTON,IL,40.4428,-87.6416,23.74.8.8
+US,PLOVER,WI,44.4117,-89.5378,184.85.215.170
+US,MONTVERNON,NH,42.9030,-71.6963,184.25.109.201
+CA,SIOUXLOOKOUT,ON,50.10,-91.92,72.246.43.232
+NE,NIAMEY,"",13.52,2.12,81.52.201.98
+RU,STROITELEY,"",56.25,43.40,80.239.217.238
+US,MICCOSUKEE,FL,30.5947,-84.0417,23.79.240.36
+FR,LEPECQ,"",48.90,2.10,2.16.117.200
+US,NORTHEASTON,MA,42.0558,-71.1216,23.62.238.220
+CN,ZHOUSHAN,ZJ,30.02,122.10,23.15.10.91
+US,JEFFERSONVILLE,IN,38.3363,-85.6984,23.220.100.223
+AT,PRIEL,"",48.45,15.57,88.221.93.150
+RU,MIR,"",58.45,39.42,2.21.240.40
+JP,KYODO,13,35.67,139.75,72.246.184.81
+US,CARRIZOSPRINGS,TX,28.4732,-99.976,96.17.163.161
+SO,HARGEISA,"",9.58,44.07,95.101.34.109
+US,FRANKENMUTH,MI,43.3550,-83.7419,184.51.35.215
+PT,EVORA,"",39.52,-8.97,195.22.14.134
+US,DOWNINGTOWN,PA,40.0250,-75.7202,23.67.242.156
+FR,DOMONT,"",49.03,2.33,2.16.117.190
+US,OAKMAN,AL,33.6727,-87.3688,184.51.35.226
+US,JENNINGS,LA,30.1991,-92.6684,23.79.240.36
+PR,BAYAMON,"",18.4008,-66.1589,192.204.82.221
+DE,NEIDLINGEN,BY,49.22,10.32,80.157.170.154
+CH,KAISERAUGST,"",47.53,7.72,193.247.167.214
+BR,OSASCO,SP,-23.57,-46.78,200.174.107.50
+FI,KUUSAMO,"",65.97,29.18,2.21.240.40
+US,BISHOP,CA,37.4772,-118.401,63.151.119.25
+US,BELLS,TX,33.6182,-96.434,23.5.164.146
+US,PARRISH,FL,27.5583,-82.2583,165.254.205.13
+DE,ZANDT,BY,49.23,10.65,195.145.147.108
+US,GARNETT,KS,38.2898,-95.2918,209.170.117.178
+US,STATHAM,GA,33.9449,-83.5889,72.246.247.5
+IR,BIRJAND,"",32.89,59.24,80.239.222.167
+US,PEARISBURG,VA,37.2475,-80.7675,184.27.45.157
+AU,RYDE,NSW,-33.82,151.10,202.7.177.87
+RO,MORENI,"",44.98,25.65,88.221.93.150
+JP,OTSU,25,35.00,135.87,117.104.139.136
+RU,SYZRAN,"",53.17,48.47,80.239.237.93
+MA,MARRAKECH,"",31.63,-8.00,2.20.44.111
+US,FUQUAYVARINA,NC,35.5406,-78.8329,209.18.41.27
+US,HOOPER,UT,41.1783,-112.1209,23.61.195.150
+US,MINERSVILLE,PA,40.6888,-76.2602,23.192.161.16
+FR,COURNONDAUVERGNE,"",45.75,3.22,2.16.117.200
+US,HATFIELD,PA,40.2766,-75.2964,23.67.242.156
+NL,WOERDEN,"",52.08,4.92,92.122.189.114
+US,ENID,OK,36.3867,-97.8158,23.5.164.143
+US,CARNEGIE,PA,40.4095,-80.1154,184.27.45.150
+NG,IBADAN,"",6.53,2.77,23.212.108.8
+FI,HAMEENLINNA,"",61.00,24.45,213.155.156.212
+BA,BANJALUKA,"",44.78,17.19,80.239.237.230
+GE,BOLNISI,"",41.45,44.54,92.122.215.67
+US,STUART,FL,27.1804,-80.2454,23.79.240.36
+CH,ARLESHEIM,"",47.48,7.62,23.14.94.214
+AT,LANDECK,"",47.13,10.57,46.33.70.97
+CZ,JICINA,"",49.57,17.97,2.20.142.173
+US,SELMER,TN,35.1420,-88.6514,23.79.240.36
+US,ORANGEPARK,FL,30.1070,-81.7167,23.79.240.36
+US,LANGHORNE,PA,40.1816,-74.9144,184.26.44.38
+IT,BRESCIA,"",45.55,10.25,95.101.34.109
+CA,MOUNTPEARL,NF,47.52,-52.78,67.69.197.95
+HK,TSUENWAN,"",22.37,114.10,23.76.205.90
+MY,LIKAS,"",5.98,116.10,96.17.180.177
+KZ,KYZYLORDA,"",44.85,65.51,217.212.227.25
+US,ONLEY,VA,37.6704,-75.7049,184.27.45.157
+RO,PASCANI,"",44.63,26.20,77.67.27.250
+CH,PREGASSONA,"",46.03,8.97,193.45.15.199
+RU,ALEXANDROV,"",56.40,38.72,2.21.240.61
+US,GRANTS,NM,35.2644,-107.7333,63.151.29.15
+US,BATTLEBORO,NC,35.8571,-77.4097,63.151.29.12
+FI,TAIVALKOSKI,"",65.57,28.25,2.21.240.61
+SK,ZILINA,"",49.22,18.73,23.14.94.214
+PL,ZORY,"",50.05,18.70,2.22.52.109
+NL,VAASSEN,"",52.28,5.97,92.122.189.114
+NO,SOGN,"",60.30,10.42,213.155.156.206
+US,OGDENSBURG,NY,44.7176,-75.3859,184.29.107.20
+AF,BAGRAM,"",34.95,69.25,2.22.52.102
+US,PALOSHEIGHTS,IL,41.6608,-87.7892,23.67.60.223
+US,GRUNDYCENTER,IA,42.3726,-92.793,23.63.227.227
+DZ,ORAN,"",35.69,-0.64,90.84.53.225
+RO,PIATRANEAMT,"",46.92,26.33,80.239.222.169
+US,BLOUNTSTOWN,FL,30.3988,-85.0821,204.2.243.132
+US,KINGGEORGE,VA,38.2650,-77.1228,208.185.55.86
+US,DIXON,IA,41.7085,-90.7516,65.113.249.11
+US,ELKRIVER,MN,45.3450,-93.5658,63.151.29.15
+JO,IRBID,"",32.56,35.85,77.67.27.235
+US,FORTRILEY,KS,38.9760,-96.6098,204.94.155.231
+US,COLDWATER,MI,41.9063,-85.0231,23.79.255.153
+US,ALICE,TX,27.6821,-98.1034,23.5.164.143
+US,HELOTES,TX,29.6143,-98.747,96.17.163.161
+US,ATMORE,AL,31.1324,-87.4695,96.6.47.106
+CA,NIAGARAONTHELAKE,ON,43.25,-79.07,72.246.43.215
+US,DELPHOS,OH,40.8243,-84.3284,23.74.8.8
+US,OKMULGEE,OK,35.6454,-96.0285,165.254.138.175
+FR,ARS,"",49.08,6.07,23.200.87.58
+AT,KATSDORF,"",48.32,14.47,195.145.147.109
+US,MIDDLEFIELD,OH,41.4619,-81.025,63.216.54.229
+SE,HACKSTA,AB,59.48,18.30,2.21.240.61
+US,SOUTHORANGE,NJ,40.7490,-74.2606,23.62.238.220
+FR,GRASSE,"",43.67,6.92,2.16.117.190
+US,AIKEN,SC,33.6484,-81.682,204.2.243.64
+SK,TOPOLCANY,"",48.57,18.18,23.62.237.133
+ZW,BULAWAYO,"",-20.15,28.58,41.193.163.45
+US,CULPEPER,VA,38.4670,-77.9818,23.67.242.139
+CN,JINCHENG,SX,35.50,112.83,72.246.191.19
+DE,BURGDORF,NI,52.15,10.22,80.157.170.154
+US,OLIN,IA,41.9909,-91.1308,65.113.249.8
+RU,ZVEZDA,"",54.11,36.78,92.122.188.163
+DE,OBERURSEL,HE,50.20,8.58,92.122.215.89
+US,FAIRPLAY,CO,39.1352,-105.9815,23.212.53.75
+IL,MIGDAL,"",32.83,35.50,212.25.69.134
+FR,EGUILLES,"",43.57,5.37,2.16.117.190
+IR,NOVIN,"",35.19,46.36,23.57.76.18
+RU,KANSK,"",56.20,95.71,184.51.199.145
+IN,THIRUVANANTHAPURAM,KL,8.51,76.96,23.211.135.66
+NZ,INVERCARGILL,"",-46.40,168.35,219.88.186.164
+US,GUNNISON,CO,38.5539,-107.0907,184.50.26.179
+US,ATWATER,CA,37.2953,-120.6669,96.17.12.44
+US,NORTHBROOKFIELD,MA,42.2695,-72.0791,184.25.157.169
+US,HARWINTON,CT,41.7549,-73.0582,63.141.200.241
+US,PAYETTE,ID,44.0773,-116.6967,206.104.149.133
+US,THIEFRIVERFALLS,MN,48.0818,-96.1186,23.79.240.36
+PL,ZABRZE,"",50.32,18.78,213.200.109.173
+FR,LESPINASSE,"",44.98,1.03,2.16.117.190
+US,MOLINE,IL,41.4843,-90.4905,65.113.249.8
+RO,RASNOV,"",45.58,25.45,81.196.26.236
+US,SHARON,PA,41.2346,-80.4992,184.27.45.157
+US,HERSHEY,PA,40.2634,-76.626,23.67.242.139
+US,BROOKSVILLE,FL,28.5914,-82.358,23.33.186.101
+CA,SAINTHUBERT,QC,47.80,-69.15,67.69.197.92
+IL,DANIEL,"",31.93,34.93,212.25.69.145
+US,GORHAM,NH,44.3296,-71.1352,107.14.38.217
+US,WINTERVILLE,NC,35.5203,-77.4072,184.28.17.55
+KE,MOMBASA,"",-4.05,39.67,2.16.1.90
+TR,COM,"",36.07,36.25,193.45.15.198
+JP,TOHO,41,33.48,129.93,72.246.184.92
+US,FORTSILL,OK,34.6684,-98.399,23.5.164.143
+US,CORTEZ,CO,37.3484,-108.7341,64.129.104.135
+US,NEWCUMBERLAND,PA,40.2034,-76.87,184.26.44.40
+US,ONEALS,CA,37.1445,-119.6517,173.223.52.67
+FI,RAISIO,"",60.48,22.18,82.96.58.85
+TR,AYDIN,"",40.17,32.68,193.45.15.198
+DE,MONTABAUR,RP,50.43,7.83,77.67.27.235
+US,LINWOOD,KS,39.0229,-95.0014,209.170.117.169
+US,PORTALLEN,LA,30.4802,-91.3238,23.215.15.22
+RU,KOMSOMOLSK,"",57.03,40.38,2.21.240.61
+US,ELONCOLLEGE,NC,36.2189,-79.4807,23.215.15.22
+US,ATHERTON,CA,37.4538,-122.2033,23.212.52.82
+US,BRAY,OK,34.6379,-97.8173,23.215.15.22
+BR,ALFENAS,MG,-21.43,-45.95,200.216.8.55
+US,SCHERERVILLE,IN,41.4906,-87.4618,107.14.38.224
+US,GURNEE,IL,42.3764,-87.9424,107.14.38.227
+US,GLOUCESTERCITY,NJ,39.8885,-75.1173,184.26.44.38
+CA,OAKVILLE,ON,43.43,-79.67,72.246.43.233
+US,DEMING,NM,32.1825,-107.7499,23.215.15.22
+PL,PABIANICE,"",51.67,19.37,80.239.222.167
+BR,POUSOALEGRE,MG,-22.22,-45.93,200.216.8.55
+TR,MUGLA,"",37.20,28.37,193.45.15.199
+US,BRYANT,AR,34.5942,-92.5003,184.28.127.55
+US,MINERALWELLS,TX,32.7965,-98.1108,23.5.164.143
+CZ,VRBNOPODPRADEDEM,"",50.12,17.38,23.62.237.135
+UZ,SAMARKAND,"",39.65,66.96,80.239.222.167
+US,SASSAMANSVILLE,PA,40.3419,-75.5728,184.26.44.38
+JP,TAMASHIMA,33,34.53,133.67,23.15.1.29
+PL,OLSZTYN,"",53.78,20.48,80.157.149.129
+US,CLAXTON,GA,32.1564,-81.8865,23.79.240.48
+US,NAHUNTA,GA,31.1753,-81.969,23.212.53.75
+US,CARRBORO,NC,35.9085,-79.0807,209.18.41.23
+AU,TOWNSVILLE,QLD,-19.25,146.80,202.7.177.76
+FR,VERNANTES,"",47.40,0.05,2.16.117.200
+US,GRANDRONDE,OR,45.1093,-123.6869,184.27.179.187
+JP,SANNO,08,35.93,140.07,23.15.1.29
+US,BAXTER,TN,36.1069,-85.6452,204.2.243.143
+CA,SACKVILLE,NB,45.88,-64.35,184.29.107.38
+RU,SYKTYVKAR,"",61.67,50.81,80.239.237.231
+DE,COBURG,BY,50.25,10.97,92.122.215.89
+CZ,HORICE,"",49.60,15.18,23.62.237.133
+US,CHESTERTON,IN,41.6139,-87.0454,23.67.60.222
+US,DENVERCITY,TX,33.0189,-102.7913,65.113.249.11
+US,KNOX,IN,41.2954,-86.6039,65.113.249.8
+US,KYLE,TX,29.9978,-97.835,23.215.15.22
+FR,CHEVIGNYSAINTSAUVEUR,"",47.30,5.13,2.16.117.200
+AT,KREMSANDERDONAU,"",48.42,15.60,195.145.147.108
+DE,KURZ,BY,47.62,12.17,23.14.94.224
+US,BELGIUM,WI,43.4979,-87.8642,107.14.38.217
+US,SHOREHAM,VT,43.8808,-73.3057,165.254.48.150
+US,BASKINGRIDGE,NJ,40.6763,-74.5643,209.170.113.124
+UA,UZHGOROD,"",48.62,22.30,2.22.52.102
+RU,PERVOURALSK,"",56.91,59.95,2.21.240.40
+RU,PLASTUN,"",44.76,136.29,96.7.251.95
+WF,MATAUTU,"",-13.28,-176.13,104.72.70.96
+US,MINEOLA,TX,32.6629,-95.4808,23.5.164.146
+US,MOSSPOINT,MS,30.4116,-88.5345,24.143.197.207
+US,GREENWICH,CT,41.0502,-73.6235,184.26.44.38
+US,ANNAPOLIS,MD,38.9918,-76.5525,23.192.161.30
+CN,XUANWU,HA,33.97,115.23,23.2.16.103
+US,MEQUON,WI,43.2406,-88.022,23.63.227.214
+HU,PESTSZENTLORINC,"",47.43,19.20,23.14.94.224
+US,INKSTER,MI,42.2932,-83.3147,23.67.60.223
+DE,BERENBERG,BW,47.90,9.03,23.14.94.214
+DE,BEVERUNGEN,NW,51.67,9.37,92.122.207.179
+CZ,HRANICE,"",49.75,14.25,23.62.237.133
+US,WOODRIDGE,IL,41.7537,-88.05,23.67.60.220
+PL,STARGARDSZCZECINSKI,"",53.33,15.05,80.239.222.167
+RS,MITROVIC,"",42.88,20.87,23.62.237.133
+US,MEDFIELD,MA,42.1847,-71.3048,184.25.109.213
+FR,CADEROUSSE,"",44.10,4.75,2.16.117.200
+RU,ZHUKOVSKIY,"",55.61,38.11,80.239.217.231
+US,WOODINVILLE,WA,47.7581,-122.094,23.212.59.85
+US,BRAZORIA,TX,28.9272,-95.5834,23.63.227.214
+US,ATCHISON,KS,39.5229,-95.1427,65.113.249.8
+AU,FINDON,SA,-34.90,138.53,23.205.117.14
+IT,CARRARA,"",44.08,10.10,193.45.15.198
+US,HOODRIVER,OR,45.5726,-121.6583,184.27.179.159
+US,MONTPELIER,VT,44.2601,-72.5759,184.25.109.200
+KW,AHMADI,"",29.08,48.08,23.212.108.8
+CN,JIEYANG,GD,23.55,116.33,107.14.44.212
+ZA,PORTELIZABETH,"",-33.97,25.58,41.193.163.53
+FR,MAXEVILLE,"",48.72,6.17,23.14.94.214
+FI,TAMPERE,"",61.50,23.75,82.96.58.85
+US,MONTAGUE,MA,42.5391,-72.5186,184.25.109.201
+IT,SANPAOLO,"",45.37,10.02,193.45.15.198
+US,FARMINGDALE,NY,40.7334,-73.4289,184.26.44.38
+US,TIJERAS,NM,34.9842,-106.3226,23.212.52.79
+US,GUTHRIE,OK,35.8319,-97.4802,23.215.15.32
+CH,ZUG,"",47.17,8.52,193.247.167.214
+US,APEX,NC,35.7358,-78.8955,96.16.12.216
+UA,MELNIK,"",49.32,25.27,23.14.94.224
+US,ODENVILLE,AL,33.6693,-86.4042,63.216.54.229
+US,MOUNTSHASTA,CA,41.3683,-122.2492,23.61.195.165
+US,COLLEGEDALE,TN,35.0534,-85.0503,184.51.35.215
+FR,GUYANCOURT,"",48.77,2.07,2.16.117.190
+HU,TISZAVASVARI,"",47.97,21.35,194.25.95.214
+US,MARTINEZ,CA,37.9788,-122.1647,23.212.52.82
+US,KEANSBURG,NJ,40.4416,-74.1294,23.67.242.156
+CZ,ZLIN,"",49.23,17.67,23.62.237.137
+DE,GOELLHEIM,RP,49.59,8.05,23.14.94.224
+US,MANGUM,OK,34.8485,-99.5641,96.16.7.101
+IN,KHAMMAM,AP,17.25,80.15,96.17.182.130
+SE,SODERHAMN,AB,59.45,18.58,107.14.32.235
+US,PARKRIDGE,IL,42.0122,-87.8435,107.14.38.224
+US,JENISON,MI,42.9189,-85.8361,65.113.249.11
+TR,ERDEM,"",37.30,40.62,77.67.27.250
+US,HAVERTOWN,PA,39.9771,-75.3116,23.67.242.156
+US,CHELMSFORD,MA,42.5915,-71.3555,23.62.238.215
+MX,CHIHUAHUA,CHH,28.63,-106.08,92.122.188.163
+US,BAYSHORE,NY,40.7379,-73.2632,184.26.44.40
+CN,XIAMEN,FJ,24.45,118.08,184.50.87.176
+US,NAUGATUCK,CT,41.4890,-73.0518,184.25.109.200
+US,WILLIAMS,AZ,35.6062,-112.4411,63.226.34.176
+US,HOBESOUND,FL,27.0409,-80.17,23.79.240.36
+TR,TRABZON,"",41.00,39.72,23.74.24.69
+US,NORTHPLATTE,NE,41.1392,-100.7774,184.85.215.170
+SK,RUZOMBEROK,"",49.08,19.32,23.62.237.133
+IN,GANDHINAGAR,GJ,23.22,72.68,23.211.135.110
+CN,CAOXIAN,SD,34.82,115.53,23.3.104.15
+US,BEARDSTOWN,IL,39.9762,-90.4107,23.63.227.214
+US,BENICIA,CA,38.1051,-122.1359,96.17.12.44
+PL,BIALA,"",51.80,20.48,2.22.52.105
+US,FORTLOUDON,PA,39.9814,-77.8809,23.192.161.30
+ID,DATA,"",-8.30,115.61,80.239.237.230
+US,BEAVERDAM,WI,43.4576,-88.8551,184.85.215.165
+US,MOUNTLAKETERRACE,WA,47.7924,-122.3065,23.212.59.63
+CA,OMPAH,ON,45.02,-76.83,209.148.192.61
+US,PENNINGTONGAP,VA,36.7557,-83.038,23.79.240.48
+US,IUKA,MS,34.8106,-88.1999,96.17.153.162
+BY,ORSHA,"",54.52,30.41,80.239.222.167
+US,TORRINGTON,WY,41.9687,-104.195,63.226.34.176
+IL,DAN,"",33.24,35.65,82.102.137.137
+US,BARRINGTON,IL,42.1512,-88.1636,107.14.38.217
+US,TEMPLETON,CA,35.5330,-120.6957,23.61.195.165
+US,SAULTSAINTEMARIE,MI,46.3629,-84.3293,23.63.227.214
+DE,MITTWEIDA,SN,50.53,12.87,2.20.142.173
+RU,DZERZHINSK,"",56.24,43.46,213.155.156.207
+US,PLEASANTVIEW,TN,36.3846,-87.0359,23.215.60.48
+US,PALISADESPARK,NJ,40.8468,-73.9958,24.143.199.188
+US,GEISMAR,LA,30.2217,-91.0044,23.215.15.9
+CN,DUYUN,GZ,26.27,107.52,72.246.191.19
+RU,NORILSK,"",69.33,88.10,217.212.227.25
+US,WAHOO,NE,41.2013,-96.6192,165.254.207.117
+US,RAYMONDVILLE,TX,26.5112,-97.8502,23.215.15.9
+AT,ERPFENDORF,"",47.58,12.47,195.145.147.101
+BG,YAMBOL,"",42.48,26.50,23.62.237.137
+US,FITCHBURG,MA,42.5924,-71.8176,184.26.44.38
+AT,PERCHTOLDSDORF,"",48.12,16.27,46.33.70.97
+RU,CHELNY,"",55.23,48.90,213.155.156.206
+IL,EINHAHORESH,"",32.38,34.93,82.102.137.137
+SE,VISBY,I,57.63,18.30,213.155.156.206
+IR,YAZD,"",31.90,54.37,77.67.96.114
+LT,GIEDRAICIU,"",55.08,25.28,2.21.240.61
+US,FAIRHOPE,AL,30.4849,-87.8614,96.17.153.162
+UA,RADIO,"",47.70,33.85,2.20.142.173
+CZ,ROUDNICENADLABEM,"",50.42,14.25,23.62.237.137
+PL,SOSNOWIEC,"",51.88,19.57,2.22.52.102
+AR,AVELLANEDA,"",-34.65,-58.38,200.123.201.219
+US,PLAINWELL,MI,42.4690,-85.5608,23.212.53.75
+US,TAHLEQUAH,OK,35.9078,-95.0047,23.215.15.9
+US,PENNSAUKEN,NJ,39.9750,-75.0476,184.26.44.38
+SE,EKSJO,F,57.67,14.95,217.212.227.25
+AT,GAUBITSCH,"",48.65,16.38,195.145.147.101
+US,WALDRON,AR,34.9204,-94.0577,209.170.117.178
+JP,NAGASAKI,42,32.80,129.92,23.3.104.29
+DZ,BEJAIA,"",36.75,5.08,92.122.189.85
+CA,ABBOTSFORD,BC,49.05,-122.30,24.244.17.205
+US,BARRE,VT,44.1738,-72.4252,72.247.10.237
+IT,SINOPOLI,"",38.27,15.88,95.101.34.109
+US,ANGWIN,CA,38.5873,-122.4459,23.61.195.163
+US,BUNKERHILL,WV,39.3176,-78.0485,184.27.45.157
+US,STRASBURG,CO,39.8693,-103.9998,184.28.23.4
+US,BYRONCENTER,MI,42.7984,-85.7381,23.67.60.222
+US,CUTBANK,MT,48.8080,-112.4878,107.14.32.235
+UA,TERNOPIL,"",49.55,25.58,2.22.52.102
+BJ,COTONOU,"",6.35,2.43,80.239.171.190
+AR,PARANA,"",-31.73,-60.53,200.123.201.219
+US,OAKHALL,VA,37.9340,-75.5755,184.25.157.162
+US,GRANTHAM,PA,40.1564,-76.9967,184.26.44.38
+US,CORINTH,MS,34.9238,-88.6234,184.27.45.157
+ER,ASMERA,"",15.33,38.93,82.102.137.137
+IN,ALWAR,RJ,27.57,76.60,96.17.182.130
+DE,STRASSE,NW,50.87,7.48,80.157.170.221
+FR,BRIVELAGAILLARDE,"",45.15,1.53,2.16.117.200
+SE,SOLBACKEN,AB,59.12,18.24,213.155.156.208
+US,AUSTINBURG,OH,41.7602,-80.8589,63.216.54.216
+CO,NARINO,"",4.40,-74.83,200.14.44.104
+CZ,PARDUBICE,"",50.03,15.78,88.221.93.157
+US,MANLIUS,NY,42.9680,-75.9513,107.14.38.227
+US,MASTICBEACH,NY,40.7682,-72.8409,184.26.44.40
+US,CHIPLEY,FL,30.6040,-85.5678,96.17.153.157
+US,COLEMAN,TX,31.8779,-99.43,173.197.194.159
+PL,SKOCZOW,"",49.80,18.80,2.22.52.101
+US,TEXARKANA,TX,33.3633,-94.2141,23.215.15.32
+DE,EDENKOBEN,RP,49.29,8.12,80.157.170.221
+PR,MOROVIS,"",18.3346,-66.4186,72.246.65.37
+US,MORRISON,CO,39.5990,-105.2281,23.63.227.214
+US,MERCERISLAND,WA,47.5624,-122.2266,23.212.59.85
+US,CONNELLSVILLE,PA,39.9618,-79.5876,209.48.37.183
+CN,YANGQUAN,SX,37.86,113.56,72.246.191.16
+TH,CHANG,"",18.85,100.82,203.144.145.96
+US,BROWNFIELD,TX,33.1115,-102.3365,63.216.54.216
+CZ,SUSICE,"",49.92,15.60,23.62.237.138
+CZ,PELHRIMOV,"",49.43,15.23,23.62.237.133
+US,RICHLANDS,VA,37.1242,-81.807,184.26.93.111
+JP,AKITA,05,39.72,140.07,96.7.251.95
+US,SIXES,OR,42.8041,-124.3226,63.217.232.17
+CZ,CERNOVICE,"",49.37,14.97,23.62.237.137
+AR,GENERALPICO,"",-35.67,-63.73,190.98.167.220
+RU,TATARSTAN,"",52.90,141.07,2.21.240.40
+US,EAGLE,ID,43.7768,-116.3919,184.27.179.187
+CN,CHANGDE,HN,29.03,111.68,117.104.139.162
+US,BONNERSFERRY,ID,48.8159,-116.6507,184.27.179.181
+US,ZEELAND,MI,42.8513,-85.9891,23.63.227.214
+DK,SKAARUP,"",54.70,11.67,23.65.29.106
+FR,SAINTGERMAINLESCORBEIL,"",48.62,2.48,2.16.117.190
+US,DARIEN,GA,31.4067,-81.499,204.2.243.132
+ES,REDES,"",43.42,-8.20,2.20.44.111
+US,CARRINGTON,ND,47.4573,-99.0752,23.79.255.149
+US,REEDCITY,MI,43.9034,-85.5104,23.63.227.227
+US,FOWLERVILLE,MI,42.6682,-84.0758,107.14.38.224
+FR,TRESSIN,"",50.60,3.20,2.16.117.200
+TH,MUANGRAJBURI,"",13.53,99.80,61.19.12.177
+RU,SUMMA,"",60.50,29.02,217.212.227.25
+US,MITCHELL,SD,43.7034,-98.0626,23.63.227.227
+CZ,JIHLAVA,"",49.40,15.58,23.62.237.137
+FR,EAUBONNE,"",49.00,2.28,2.16.117.200
+BG,BISTRICA,"",42.23,23.17,92.122.215.89
+US,UVALDE,TX,29.3417,-99.8887,107.14.36.199
+IN,DWARKA,GJ,22.24,68.97,2.21.240.40
+US,LITHIASPRINGS,GA,33.7656,-84.6415,23.79.240.48
+US,LENORA,KS,39.6800,-99.7571,23.77.234.35
+AU,POTTSPOINT,NSW,-33.87,151.22,23.62.8.25
+US,HAINES,AK,59.1202,-135.7004,24.244.17.205
+NO,KVITESEID,"",59.40,8.50,213.155.156.206
+BD,COMILLA,"",23.45,91.20,23.57.76.18
+US,RICHFIELD,UT,38.7083,-111.7291,23.61.195.163
+GB,GATWICK,EN,51.17,-0.18,23.212.108.8
+US,LILLINGTON,NC,35.3213,-78.9874,184.28.127.58
+US,GREENACRES,WA,47.6286,-117.1038,206.104.149.146
+US,GRANTSVILLE,MD,39.6703,-79.1506,184.26.44.38
+CZ,RAKOVNIK,"",50.10,13.75,23.62.237.137
+US,PETAL,MS,31.3432,-89.178,96.17.153.162
+CZ,MNICHOVICE,"",49.93,14.70,23.62.237.137
+US,HOHENWALD,TN,35.5255,-87.548,23.79.240.36
+US,PECULIAR,MO,38.7126,-94.4101,23.212.53.75
+CN,YIGAO,ZJ,30.93,120.29,72.246.191.19
+CN,JILIN,JL,43.86,126.57,184.51.199.132
+IN,UDHAMPUR,JK,32.93,75.13,117.239.91.75
+PL,OBORNIKISLASKIE,"",51.30,16.92,2.22.61.102
+US,HEDGESVILLE,WV,39.5195,-78.0934,23.192.161.30
+FR,LEOGNAN,"",44.73,-0.60,2.16.117.190
+RO,GHEBOAIA,"",44.80,25.75,2.22.52.109
+US,WILLCOX,AZ,32.5598,-110.08,63.226.34.172
+DE,SANDESNEBEN,SH,53.68,10.50,92.122.207.179
+FR,AVALLON,"",47.48,3.90,2.16.117.200
+US,HAVREDEGRACE,MD,39.5690,-76.1506,165.254.48.142
+IL,ASHDOD,"",31.82,34.65,212.25.69.142
+KE,NAKURU,"",-0.28,36.07,2.16.1.106
+US,TRUCKEE,CA,39.3282,-120.1822,23.5.164.143
+US,MARIANNA,FL,30.7390,-85.2383,23.79.240.36
+UA,MARIUPOL,"",47.10,37.55,80.239.237.230
+RO,CAREI,"",47.68,22.47,81.196.26.231
+US,WESTFRANKFORT,IL,37.9074,-88.9501,165.254.207.117
+HU,TEGLAS,"",47.72,21.68,23.14.94.228
+NL,SHERTOGENBOSCH,"",51.70,5.32,2.16.153.173
+US,LINCOLNWOOD,IL,42.0082,-87.731,23.67.60.223
+US,BROADVIEWHEIGHTS,OH,41.3194,-81.6781,96.17.9.8
+US,GALESBURG,IL,40.9508,-90.3832,65.113.249.11
+PL,KUZNIARACIBORSKA,"",50.20,18.30,213.200.109.183
+US,GIBSONIA,PA,40.6378,-79.9434,209.48.37.188
+AU,MONASH,SA,-34.23,140.57,104.72.70.96
+CA,BANFF,AB,51.17,-115.57,24.244.17.205
+IR,PASARGAD,"",30.20,53.18,23.14.94.214
+US,INWOOD,WV,39.3765,-78.0298,23.192.161.30
+MX,SANANDRESCHOLULA,PUE,19.05,-98.30,23.215.15.22
+AT,PIRKA,"",47.00,15.38,195.145.147.109
+US,DYERSBURG,TN,36.0753,-89.423,23.220.100.224
+US,CEDAR,MN,45.3385,-93.2617,23.67.60.223
+US,APPLING,GA,33.6237,-82.2874,23.79.240.36
+US,MERRIMACK,NH,42.8551,-71.5193,209.170.113.237
+CA,VANDERHOOF,BC,54.02,-124.02,24.244.17.205
+US,EMMAUS,PA,40.5173,-75.5037,23.67.242.139
+US,CRANBERRYTWP,PA,40.6999,-80.1268,96.6.47.120
+CN,YIZHUANG,JS,34.17,117.58,184.50.87.178
+US,FRASER,MI,42.5384,-82.9497,69.22.154.209
+RS,IN,"",43.45,19.32,2.20.45.102
+HK,TUENMUN,"",22.40,113.98,23.76.205.111
+US,OCEANSPRINGS,MS,30.4180,-88.7558,165.254.138.165
+TG,LOME,"",6.13,1.22,77.67.41.227
+US,JACKSONVILLEBEACH,FL,30.3318,-81.6555,23.79.240.36
+US,WINSLOW,AZ,35.1934,-110.3619,65.116.149.102
+US,MAGNA,UT,40.7034,-112.1122,184.50.26.179
+UA,KALUSH,"",49.02,24.37,2.20.142.173
+US,WINOOSKI,VT,44.4955,-73.1839,165.254.48.150
+US,PINETOWN,NC,35.6052,-76.8394,184.28.17.55
+HU,SZEKESFEHERVAR,"",47.20,18.42,23.14.94.228
+FR,MARTRESDEVEYRE,"",45.68,3.20,88.221.83.118
+GR,KAVALA,"",40.94,24.40,93.186.137.228
+DK,ARHUS,"",56.15,10.22,213.155.156.206
+CN,ZHANGZHOU,FJ,24.52,117.67,184.50.87.176
+IN,KHARAGPUR,WB,22.33,87.33,96.17.182.130
+US,SAFETYHARBOR,FL,28.0080,-82.6963,23.33.186.101
+MG,ANTSIRABE,"",-19.85,47.03,195.10.8.202
+IL,MAGEN,"",31.30,34.43,212.25.69.136
+TH,BANKOK,"",13.58,100.22,88.221.15.111
+US,HOLMDEL,NJ,40.3764,-74.1727,23.220.148.122
+US,MONTEVALLO,AL,33.1388,-86.8879,23.79.240.36
+GB,SEACROFT,EN,53.82,-1.45,23.67.255.106
+FR,SAINTCHAMOND,"",45.47,4.50,2.16.117.212
+PW,KOROR,"",7.33,134.48,23.76.205.111
+US,BELEN,NM,34.5756,-106.5882,23.61.195.165
+US,MONAHANS,TX,31.5378,-102.956,64.145.95.141
+US,QUITMAN,GA,30.7559,-83.5353,184.84.180.68
+DE,PUCHHEIM,BY,48.15,11.35,84.53.175.92
+US,FAITH,SD,44.8511,-102.1289,23.74.8.61
+CN,DAQING,HL,46.58,125.00,184.51.199.132
+US,LAGUNABEACH,CA,33.5745,-117.7868,184.50.26.192
+IQ,SULAYMANIYAH,"",34.03,44.82,195.145.147.107
+US,FAIRVIEWHEIGHTS,IL,38.5952,-90.0039,204.93.47.220
+US,BALLSTONSPA,NY,43.0020,-73.8759,107.14.38.217
+FR,SAINTPRIEST,"",46.45,2.17,2.16.117.190
+US,ALAMOSA,CO,37.4690,-105.8365,107.14.32.228
+CN,LEDONG,HI,18.75,109.17,72.246.191.19
+US,MARGARETVILLE,NY,42.1471,-74.6599,165.254.48.155
+RO,BANCA,"",46.35,27.28,2.22.52.101
+PL,USTKA,"",54.58,16.85,77.67.96.114
+US,RINCON,GA,32.2490,-81.2731,23.79.240.36
+AT,STEINHAUS,"",47.62,15.80,195.145.147.109
+US,MADISONHEIGHTS,MI,42.5080,-83.103,23.63.227.227
+RU,NAKHODKA,"",51.63,43.97,80.239.237.231
+IN,PONDICHERRY,PY,11.93,79.83,80.239.237.230
+NA,TSUMEB,"",-19.23,17.72,41.193.163.45
+US,INDIANTRAIL,NC,35.0963,-80.6145,209.18.41.27
+RU,RAY,"",58.30,40.12,80.239.237.231
+PL,FRANK,"",53.90,18.25,2.22.52.101
+TH,KRABI,"",8.07,98.92,203.106.85.113
+RU,YEISK,"",46.70,38.28,2.22.52.102
+US,BARNSTABLE,MA,41.7011,-70.3019,184.25.109.196
+CN,TONGLING,AH,30.95,117.78,184.50.87.178
+DE,PFORZHEIM,BW,48.88,8.70,23.14.94.214
+US,COOPERSTOWN,NY,42.7228,-74.8929,209.18.41.27
+US,VALENTINE,NE,42.4840,-100.7562,184.27.120.65
+HU,HAJDUNANAS,"",47.85,21.43,23.14.94.228
+PR,ARECIBO,"",18.4739,-66.7295,72.164.253.83
+FR,BOBIGNY,"",48.90,2.45,90.84.50.230
+US,POWHATAN,VA,37.5492,-77.935,63.130.161.239
+TW,CHANGHUA,"",24.08,120.53,23.76.205.111
+US,STEUBENVILLE,OH,40.3582,-80.6994,184.28.17.76
+PH,TONDO,"",14.62,120.97,184.84.239.186
+DK,GALTEN,"",56.15,9.92,2.21.240.40
+NL,MIERLO,"",51.45,5.62,95.101.2.112
+UA,BERDYANSK,"",46.75,36.79,2.21.240.61
+VN,TRAI,"",17.12,106.95,184.84.239.175
+US,POWELL,OH,40.1701,-83.0808,107.14.38.227
+US,FAIRFAXSTATION,VA,38.7497,-77.3141,23.212.53.64
+AT,WELS,"",48.17,14.03,23.14.94.228
+US,LAMPASAS,TX,31.1064,-98.2303,96.17.163.161
+US,VILLAPARK,IL,41.8812,-87.9751,107.14.38.224
+US,NEWLEXINGTON,OH,39.7095,-82.1925,107.14.38.224
+MY,BATUPAHAT,"",1.85,102.93,203.106.85.195
+US,SHIRLEY,NY,40.7965,-72.8753,23.61.195.165
+BA,GRUDE,"",43.81,17.45,23.14.94.228
+AR,CARBONI,"",-35.20,-59.33,190.98.167.220
+US,BELLWOOD,IL,41.8827,-87.8764,23.67.60.223
+US,EXCELSIOR,MN,44.8924,-93.5895,23.67.60.217
+US,CEDARTOWN,GA,33.9973,-85.2758,72.246.247.30
+PL,SWINOUJSCIE,"",53.92,14.25,2.22.52.109
+US,NEOSHO,MO,36.8753,-94.3946,23.77.234.11
+VN,THUDUC,"",10.85,106.75,23.5.165.167
+CH,SCHAFFHAUSEN,"",47.70,8.63,193.247.167.214
+JP,SAKAE,30,33.65,135.40,23.61.250.108
+US,CHAPIN,SC,34.1436,-81.3335,209.18.41.27
+US,HOLLY,MI,42.7970,-83.603,184.27.120.65
+US,HARDIN,MT,45.8343,-107.7879,67.131.104.6
+BE,HASSELT,"",50.93,5.33,23.62.100.154
+JP,ASAHIKAWA,01,43.77,142.37,72.246.184.81
+RU,YUZHNOSAKHALINSK,"",46.95,142.74,96.7.251.97
+US,JOHNSISLAND,SC,32.6897,-80.0874,96.16.12.216
+US,LEITCHFIELD,KY,37.4975,-86.3182,63.216.54.216
+US,BASIN,WY,44.3702,-108.0775,184.27.179.181
+GB,STAPLE,EN,51.25,1.25,92.122.54.12
+UA,KREMENCHUK,"",49.07,33.42,80.239.149.123
+PK,SIALKOT,"",30.92,71.85,165.254.144.25
+US,RANDOMLAKE,WI,43.5753,-87.9876,23.79.255.149
+BG,RUSE,"",43.83,25.95,2.20.45.104
+US,BRAINERD,MN,46.2895,-94.0683,65.113.249.8
+CO,CUCUTA,"",7.90,-72.52,190.90.221.149
+US,BELLEGLADE,FL,26.5243,-80.6241,184.28.184.6
+IN,TADEPALLEGUDEM,AP,16.83,81.50,23.205.118.106
+US,MANDAN,ND,46.7289,-100.9833,107.14.38.217
+US,STREETSBORO,OH,41.2431,-81.3428,107.14.38.217
+BG,BALKAN,"",41.77,25.57,93.186.137.228
+US,WOODBINE,MD,39.3345,-77.0694,184.27.45.150
+GB,LANCING,EN,50.82,-0.33,173.222.211.190
+US,MERIDEN,CT,41.5330,-72.7742,184.29.107.38
+US,HAYMARKET,VA,38.8726,-77.6484,23.192.161.21
+US,DEDHAM,MA,42.2464,-71.1775,184.25.109.213
+SE,LUND,M,55.70,13.18,23.65.29.106
+MF,MARIGOT,"",18.07,-63.08,2.20.243.45
+GR,KALAMAKI,"",37.92,23.72,23.14.94.214
+FR,MAROLLESENHUREPOIX,"",48.57,2.30,2.16.117.200
+DE,WETZLAR,HE,50.55,8.50,92.122.207.179
+NA,WALVISBAY,"",-22.96,14.51,41.193.163.45
+BR,CRICIUMA,PR,-26.02,-51.72,187.59.4.147
+US,SKOWHEGAN,ME,44.8163,-69.6519,165.254.48.155
+MZ,MOCAMBIQUE,"",-17.07,36.75,165.165.46.38
+CN,YUNCHENG,SX,35.02,110.99,72.246.191.16
+US,NEWPORTCOAST,CA,33.5768,-117.7458,184.50.26.204
+US,SHAMOKINDAM,PA,40.8488,-76.8203,184.26.44.40
+SL,FREETOWN,"",8.49,-13.23,63.80.12.205
+US,GRASONVILLE,MD,38.9427,-76.1976,168.143.243.33
+US,FORSYTH,GA,33.0857,-83.918,72.246.247.30
+CZ,JICIN,"",50.43,15.35,2.20.142.166
+TR,TUZLA,"",40.50,30.52,23.62.237.138
+US,GRAFTON,WI,43.3305,-87.9299,65.113.249.8
+US,FREEBURG,IL,38.3845,-89.9186,96.17.14.15
+BE,MARAIS,"",50.55,4.32,23.62.100.154
+SA,YANBU,"",24.09,38.05,23.215.60.48
+US,KINGSMOUNTAIN,NC,35.2471,-81.3891,96.16.12.228
+US,TAOS,NM,36.4227,-105.5099,204.2.223.91
+US,CHICKASHA,OK,34.9953,-97.9747,173.197.194.159
+US,NATCHITOCHES,LA,31.7831,-93.1496,23.5.164.143
+US,EDEN,NY,42.6450,-78.8782,107.14.38.218
+US,EDGEWOOD,MD,39.4327,-76.2984,184.27.45.150
+US,SACO,ME,43.5496,-70.476,107.14.38.218
+CA,YARMOUTH,NS,43.83,-66.12,184.27.45.150
+US,MARLBORO,NJ,40.3194,-74.2497,184.26.44.38
+DE,LUNEBURG,NI,53.25,10.40,195.95.193.147
+US,LITCHFIELDPARK,AZ,33.5445,-112.5171,184.50.26.201
+GB,STOCKTONONTEES,EN,54.58,-1.42,23.67.255.106
+US,COMMERCE,TX,33.3007,-95.9347,184.26.93.116
+SK,PRESOV,"",49.00,21.25,23.62.237.137
+DZ,BATNA,"",35.56,6.18,77.67.96.114
+US,RUNNEMEDE,NJ,39.8519,-75.0768,23.67.60.223
+MZ,MOZAMBIQUE,"",-15.03,40.74,41.193.163.45
+US,BOALSBURG,PA,40.7669,-77.7668,23.192.161.16
+AU,BENDIGO,VIC,-36.77,144.28,210.11.142.67
+CZ,TABOR,"",49.42,14.67,23.62.237.138
+US,BERRIENSPRINGS,MI,41.9566,-86.3987,23.67.60.217
+US,HOLLIDAYSBURG,PA,40.4448,-78.3256,184.28.17.55
+NO,BODO,"",67.28,14.38,213.155.156.206
+RU,DIVNOGORSK,"",55.96,92.36,2.21.240.40
+US,REDHOUSE,WV,38.5624,-81.9059,184.28.17.76
+AT,NEUHAUS,"",48.00,16.05,195.145.147.101
+CN,XINGYI,GZ,25.05,104.98,72.246.191.16
+HK,WANCHAI,"",22.28,114.17,23.76.205.90
+ID,LUWUK,"",-6.28,106.18,23.0.162.40
+US,BATTLEGROUND,WA,45.8003,-122.4981,23.212.59.85
+DE,INGOLSTADT,BY,48.77,11.43,92.122.207.164
+FI,KOKKOLA,"",61.50,28.20,92.122.215.89
+RO,ROMAN,"",46.92,26.92,88.221.93.157
+AT,KLAGENFURT,"",46.62,14.31,195.145.147.109
+AU,MARIBYRNONG,VIC,-37.78,144.88,60.254.143.211
+US,SLOUGHHOUSE,CA,38.5091,-121.107,128.241.89.70
+US,VILLEPLATTE,LA,30.7127,-92.2634,23.212.53.64
+DE,OBERHAUSEN,NW,51.47,6.85,2.20.142.166
+GB,SALFORD,EN,52.03,-0.63,88.221.87.94
+GB,GIFFORD,SC,55.90,-2.73,23.212.108.28
+US,BALDWINSVILLE,NY,43.1825,-76.3664,184.26.44.40
+NO,ARENDAL,"",58.46,8.77,2.21.240.40
+IN,NAMAKKAL,TN,11.23,78.17,23.205.118.106
+CZ,HODONIN,"",49.83,15.78,195.27.155.188
+US,MANOR,TX,30.3520,-97.5205,96.17.163.161
+PL,ISKRZYCZYN,"",49.82,18.75,23.74.24.69
+CN,WUHU,AH,31.35,118.37,184.50.87.178
+UA,KRAMATORSK,"",48.72,37.53,80.239.237.231
+AR,LUJAN,"",-34.57,-59.10,2.21.240.40
+DE,NUSSE,SH,53.67,10.58,92.122.207.179
+NL,EDE,"",52.03,5.67,95.101.2.112
+US,OWATONNA,MN,44.0575,-93.2082,184.85.215.165
+US,SCIO,OR,44.6708,-122.6996,23.212.59.85
+FI,SEINAJOKI,"",62.80,22.83,2.21.240.40
+US,CHERRYVILLE,NC,35.3791,-81.3649,96.16.12.216
+IN,ATTUR,TN,12.73,79.95,23.205.118.106
+PH,TOWER,"",6.18,125.13,23.76.205.111
+US,TRUSSVILLE,AL,33.6426,-86.5754,165.254.138.175
+PT,PRIME,"",40.63,-7.83,195.22.14.133
+ES,MORON,"",41.42,-2.42,2.20.44.118
+CZ,KTIS,"",48.92,14.13,23.62.237.133
+CZ,NYRANY,"",49.72,13.20,195.27.155.188
+US,BONNERSPRINGS,KS,39.0619,-94.8881,23.77.234.35
+BA,BRCKO,"",44.88,18.81,95.101.34.105
+US,GODDARD,KS,37.6682,-97.5892,174.76.226.117
+US,PELZER,SC,34.6459,-82.4278,23.79.240.36
+US,GRANVILLE,OH,40.0812,-82.5297,77.67.86.217
+AU,ROSEBERY,NSW,-33.92,151.20,202.7.177.87
+US,LOUDONVILLE,OH,40.6534,-82.2246,23.74.8.8
+AU,ULTIMO,NSW,-33.88,151.20,104.72.70.96
+DE,BOTTROP,NW,51.52,6.92,2.22.61.99
+GR,KOZANI,"",40.30,21.78,23.14.94.228
+US,LAKEOZARK,MO,38.2106,-92.6582,204.93.47.220
+US,GLENCARBON,IL,38.7582,-89.9728,23.212.53.75
+NG,ODUA,"",4.92,6.45,90.84.53.225
+US,SMARR,GA,32.9834,-83.8751,63.234.249.61
+US,BELLEVERNON,PA,40.1536,-79.8119,23.192.161.16
+US,WINNFIELD,LA,31.8850,-92.6017,23.5.164.146
+HU,ANGYALFOLD,"",47.53,19.07,23.14.94.228
+US,CARO,MI,43.4866,-83.3855,65.113.249.8
+US,IGNACIO,CO,37.0891,-107.6496,64.129.104.132
+ID,MADIUN,"",-7.62,111.52,23.0.162.40
+US,PERRYSVILLE,OH,40.6625,-82.3165,23.215.15.22
+UA,KHIZHA,"",48.10,23.20,192.80.13.117
+IT,PARCO,"",38.05,13.30,96.17.180.155
+US,HEPHZIBAH,GA,33.2810,-82.1107,23.79.240.36
+US,DETROITLAKES,MN,46.9503,-95.6596,198.63.196.214
+US,HEBRON,KY,39.0882,-84.7043,107.14.38.217
+IN,ABHANPUR,CT,21.05,81.72,124.124.252.159
+US,LITTLERIVER,SC,33.8867,-78.6627,209.18.41.27
+IN,KANPUR,UP,26.47,80.35,23.57.76.18
+US,CHARDON,OH,41.5761,-81.1919,107.14.38.218
+HU,BALATON,"",48.10,20.32,23.14.94.214
+GM,BANJUL,"",13.45,-16.58,23.76.205.90
+US,TWINSBURG,OH,41.3169,-81.4404,107.14.38.218
+US,MOUNTPOCONO,PA,41.1358,-75.3944,23.67.242.156
+RO,TATARANI,"",44.90,26.03,80.239.222.169
+DZ,BLIDA,"",36.47,2.83,213.248.108.244
+US,SILOAMSPRINGS,AR,36.1693,-94.458,23.215.15.9
+AT,GROSSENDORF,"",48.05,14.05,195.145.147.109
+US,SEVERN,MD,39.1227,-76.6832,23.192.161.16
+RU,KURILSK,"",45.23,147.88,77.67.27.235
+US,BIRDSBORO,PA,40.2313,-75.8555,63.216.54.231
+US,BARBOURVILLE,KY,36.8650,-83.9507,184.27.45.150
+AR,ROJAS,"",-34.20,-60.73,80.239.237.230
+US,PALATINE,IL,42.1106,-88.0342,107.14.38.227
+RU,ULANUDE,"",51.83,107.62,184.51.199.145
+CA,CASTLEGAR,BC,49.32,-117.67,184.27.179.159
+AR,RIOCUARTO,"",-33.13,-64.35,80.239.237.231
+US,BURLINGAME,CA,37.5670,-122.3669,96.17.12.44
+US,KOHLER,WI,43.7428,-87.7817,23.74.8.24
+IN,GANDHIDHAM,GJ,23.08,70.13,23.211.135.66
+US,POULSBO,WA,47.7571,-122.6233,165.254.1.165
+KR,TAEGU,"",35.87,128.60,125.56.214.166
+RU,PENZA,"",53.20,45.00,2.22.52.109
+TR,BOGAZICI,"",37.52,30.07,23.14.94.224
+RU,PANFILOVA,"",56.00,39.10,2.21.240.61
+US,WESTLAKE,LA,30.2637,-93.2773,23.215.15.22
+BR,LIMEIRA,SP,-22.56,-47.40,187.59.4.154
+US,WOODRUFF,SC,34.7461,-82.0164,165.254.138.175
+US,GOLDTHWAITE,TX,31.3914,-98.5866,23.212.53.75
+CA,GASPE,QC,48.83,-64.48,184.27.120.65
+PL,BIALAPODLASKA,"",52.03,23.13,77.67.96.114
+US,FORTEDWARD,NY,43.2300,-73.5588,107.14.38.217
+US,BONAIRE,GA,32.5074,-83.5644,184.51.35.226
+US,LONGPOND,PA,41.0663,-75.4541,184.26.44.38
+IR,CHAMRAN,"",35.17,49.93,77.67.96.114
+US,NEWBOSTON,TX,33.4799,-94.4582,23.215.15.9
+TR,GENEL,"",40.88,39.57,23.74.24.66
+US,PROSPECT,KY,38.3571,-85.5869,107.14.38.217
+US,CLOVER,SC,35.1039,-81.2451,72.246.247.5
+US,RANCHOMIRAGE,CA,33.7825,-116.4136,184.50.26.192
+US,OLNEY,IL,38.7221,-88.0876,23.74.8.8
+US,MADRAS,OR,44.6442,-121.0642,67.131.104.14
+DE,LINDAU,BY,47.55,9.68,195.145.147.109
+US,ZEBULON,NC,35.8277,-78.3112,96.16.12.216
+US,BAKERCITY,OR,44.7595,-117.7162,165.254.144.32
+US,HUGOTON,KS,37.1182,-101.3229,23.215.15.22
+DE,ESPELKAMP,NW,52.38,8.62,92.122.207.179
+UA,GORODOK,"",49.60,29.20,2.22.52.109
+FR,TASSIN,"",45.77,4.78,2.16.117.190
+CA,MALTON,ON,43.70,-79.63,72.246.43.237
+SG,TAISENG,"",1.34,103.90,124.155.222.130
+DE,ALBERT,BW,47.58,8.12,80.157.170.154
+FR,SAINTDIDIERENVELAY,"",45.30,4.28,2.16.117.190
+FR,BONDY,"",48.90,2.47,2.16.117.200
+CZ,KURIM,"",49.30,16.53,2.22.52.102
+US,GLENWOODSPRINGS,CO,39.6119,-107.29,23.212.53.75
+US,LITTLESTOWN,PA,39.7552,-77.119,212.25.69.145
+RU,SOCHI,"",43.60,39.73,2.21.240.61
+CA,TIVERTON,ON,44.27,-81.54,209.148.192.61
+US,VINTON,VA,37.2726,-79.7653,23.220.148.108
+AU,SHEPPARTON,VIC,-36.38,145.40,202.7.177.87
+US,BRASELTON,GA,34.1410,-83.7809,23.79.240.48
+FI,NOKIA,"",61.47,23.50,95.101.2.122
+RU,YUG,"",56.25,56.05,2.21.240.61
+AT,LEBRING,"",46.85,15.54,195.145.147.107
+NL,NIJMEGEN,"",51.83,5.87,92.122.189.114
+IT,SESTO,"",45.53,9.23,193.45.15.198
+FI,ALAJARVI,"",63.00,23.82,2.21.240.40
+HU,DEBRECEN,"",47.53,21.63,23.14.94.220
+DE,SAARBURG,RP,49.60,6.55,95.101.2.112
+RO,BUSTENI,"",45.40,25.53,81.196.26.198
+UA,CHERNIHIV,"",51.50,31.30,23.14.94.224
+US,LAKEGENEVA,WI,42.5685,-88.4719,107.14.38.217
+IN,TEKANPUR,MP,25.98,78.27,96.17.182.130
+US,NORTHBEND,OR,43.4574,-123.9916,184.27.179.179
+RO,SIGHETUMARMATIEI,"",47.93,23.88,81.196.26.236
+US,GIDDINGS,TX,30.1637,-96.9376,65.116.149.89
+US,KANAB,UT,37.2711,-111.7696,165.254.137.75
+FR,CARPENTRAS,"",44.05,5.05,2.16.117.190
+PL,DZIALDOWO,"",53.23,20.18,2.22.52.101
+US,CHEBOYGAN,MI,45.5327,-84.3636,23.63.227.227
+PL,SUPRASL,"",53.22,23.35,80.157.149.129
+DE,HERFORD,NW,52.13,8.68,92.122.207.179
+US,CALIFORNIACITY,CA,35.1256,-117.9853,184.50.26.194
+DE,MONCHENGLADBACH,NW,51.20,6.43,80.157.170.158
+AU,GEELONG,VIC,-38.16,144.35,104.72.70.96
+US,OAKGROVE,MO,39.0160,-94.144,23.67.60.222
+RU,VYAZMA,"",56.49,35.78,80.239.222.169
+US,ISELIN,NJ,40.5710,-74.3169,184.26.44.38
+PL,CHOJNICE,"",53.70,17.57,80.239.222.169
+US,ATTALLA,AL,34.0771,-86.0689,23.79.240.36
+US,GATESVILLE,TX,31.4272,-97.7097,23.215.15.9
+IT,CARBONE,"",38.23,16.25,23.76.205.111
+US,PRESTONSBURG,KY,37.6405,-82.8256,184.27.45.157
+RS,NOVISAD,"",45.25,19.84,2.20.45.104
+CH,UITIKON,"",47.37,8.47,193.45.15.199
+SE,BORLANGE,W,60.48,15.42,82.96.58.85
+US,PINEGROVE,CA,38.4023,-120.6508,63.217.232.17
+US,TECUMSEH,OK,35.2189,-97.0168,205.185.195.170
+IT,STELLA,"",44.45,10.80,2.18.240.114
+FI,KOUVOLA,"",60.33,24.15,213.155.156.207
+DE,CRIMMITSCHAU,SN,50.82,12.38,195.95.193.150
+US,CIBOLO,TX,29.5774,-98.2236,23.5.164.146
+FR,LANGUEUX,"",48.50,-2.72,2.16.117.200
+US,EASTPROSPECT,PA,39.9710,-76.5165,23.192.161.21
+US,ELRENO,OK,35.5525,-97.9651,23.215.15.22
+US,LOUISIANA,MO,39.4061,-91.0955,96.17.14.16
+US,EUFAULA,AL,31.9293,-85.2612,72.246.247.5
+SE,OSTERSUND,Z,63.18,14.65,2.21.240.40
+US,WARRENVILLE,IL,41.8320,-88.2281,23.67.60.220
+US,GROVER,MO,38.5699,-90.6264,96.17.14.15
+US,CIRCLEPINES,MN,45.1631,-93.1211,23.67.60.223
+US,THERMOPOLIS,WY,43.7189,-108.4422,184.27.179.159
+FR,VENISSIEUX,"",45.68,4.88,2.16.117.200
+LT,NAUJOJIAKMENE,"",56.32,22.90,217.212.227.25
+RO,SEBES,"",45.72,25.03,81.196.26.198
+US,TERRABELLA,CA,35.9407,-119.0558,65.113.249.8
+VI,CHARLOTTEAMALIE,"",18.3436,-64.9314,192.204.11.246
+US,CRAIG,CO,40.7169,-107.7139,107.14.32.235
+CH,WINTERTHUR,"",47.50,8.75,193.247.167.214
+AU,OAKLEIGH,VIC,-37.90,145.10,60.254.143.211
+IT,TORREPELLICE,"",44.82,7.22,2.18.240.95
+US,NEWPALESTINE,IN,39.7310,-85.9032,23.67.60.217
+FR,MAYENNE,"",48.30,-0.62,2.16.117.190
+JP,ICHINOSEKI,03,38.92,141.13,72.246.191.16
+GB,SIDMOUTH,EN,50.68,-3.25,72.246.43.237
+DE,OFFENBACH,HE,50.10,8.77,84.53.146.39
+US,DIBERVILLE,MS,30.4863,-88.9554,165.254.138.165
+TH,CHONBURI,"",13.37,100.98,61.19.12.164
+IN,KOL,UL,30.50,77.92,23.57.69.161
+JP,HIKARI,35,33.96,131.95,118.155.230.136
+SG,CHANGI,"",1.34,103.96,23.75.23.135
+US,OAKLYN,NJ,39.9079,-75.0838,184.26.44.38
+US,HILLIARD,OH,40.0220,-83.1807,107.14.38.227
+US,CARLSTADT,NJ,40.8256,-74.0623,23.67.244.226
+AT,FIEBERBRUNN,"",47.48,12.55,195.145.147.108
+US,VERMILLION,SD,42.8915,-96.9263,23.212.53.64
+US,WALL,SD,43.9288,-102.204,23.63.227.214
+IR,SARI,"",36.57,53.06,96.17.182.130
+SK,VELICNA,"",49.22,19.25,23.14.94.220
+US,PELLA,IA,41.4226,-92.9246,63.216.54.229
+AR,PUNTAALTA,"",-38.88,-62.08,190.98.167.220
+MX,CIUDADVICTORIA,TAM,23.73,-99.13,165.254.16.86
+US,SOUTHGLENSFALLS,NY,43.2897,-73.6312,107.14.38.217
+US,PARLIN,NJ,40.4576,-74.306,184.26.44.38
+US,OGALLALA,NE,41.0603,-101.6294,23.215.15.22
+PH,PASAY,"",14.55,121.00,58.71.107.119
+CZ,ZNOJMO,"",48.85,16.05,23.62.237.135
+NL,LEEUWARDEN,"",53.20,5.78,2.16.153.150
+RU,SATIS,"",54.82,43.13,213.155.156.212
+IT,ROZZANO,"",45.37,9.15,195.22.200.221
+US,MARTINSVILLE,VA,36.7249,-79.8574,184.26.44.38
+DE,RHEIN,NW,50.85,7.70,2.20.142.166
+IN,RATNAGIRI,MH,16.98,73.30,117.239.240.96
+AT,DIETACH,"",48.08,14.42,195.145.147.109
+CA,SAINTEUSTACHE,QC,45.57,-73.90,67.69.197.92
+US,POULTNEY,VT,43.5323,-73.1932,165.254.48.155
+US,CHANHASSEN,MN,44.8569,-93.5486,204.93.47.216
+TH,NUA,"",18.65,101.03,202.183.253.37
+US,CRESTWOOD,KY,38.3420,-85.4306,23.220.100.223
+CA,HEARST,ON,49.70,-83.67,72.246.43.237
+AT,THERESIENFELD,"",47.85,16.23,195.145.147.108
+FR,FROMONT,"",48.25,2.50,2.16.117.200
+ID,CIANJUR,"",-6.82,107.13,23.0.162.21
+US,PAPILLION,NE,41.1138,-96.0413,23.79.255.153
+KZ,ZHEZKAZGAN,"",47.78,67.77,217.212.227.31
+US,THOMSON,GA,33.5142,-82.516,23.79.240.36
+CR,GUADALUPE,"",9.95,-84.05,23.74.2.7
+PT,BARCARENA,"",38.73,-9.28,195.22.14.134
+TM,TURKMENISTAN,"",40.47,62.22,2.20.142.166
+US,BARRON,WI,45.3978,-91.8834,23.74.8.8
+US,MABANK,TX,32.3389,-96.1042,23.212.53.75
+US,RUSK,TX,31.7956,-95.1946,67.131.44.150
+US,PINSON,AL,33.7345,-86.6508,23.220.100.223
+CZ,CHRUDIM,"",49.95,15.80,23.62.237.138
+US,HALLETTSVILLE,TX,29.3984,-96.8256,23.215.15.22
+US,CASSELTON,ND,46.8908,-97.241,23.74.8.24
+IE,GALWAY,"",53.27,-9.05,88.221.222.33
+JP,YAMANASHI,22,34.80,137.90,72.246.191.16
+IN,CHANDAUSI,UP,28.45,78.77,23.205.118.106
+IN,KALAMBOLI,MH,19.03,73.10,96.17.180.155
+US,HAYTI,MO,36.2659,-89.7083,96.17.14.15
+CN,SANMING,FJ,26.40,117.20,184.84.239.175
+DE,BINDLACH,BY,49.98,11.61,23.74.24.69
+CH,MURTEN,"",46.93,7.12,213.254.212.102
+US,SAMMAMISH,WA,47.6302,-122.0537,23.212.59.63
+AU,SOUTHYARRA,VIC,-37.83,144.98,23.205.116.7
+UA,SUMY,"",50.92,34.78,80.239.222.190
+US,KUNA,ID,43.3407,-116.2859,206.104.149.146
+PL,BARCINWIES,"",52.88,17.95,2.22.52.101
+US,TANEYTOWN,MD,39.6723,-77.1742,23.67.242.156
+US,PARKRAPIDS,MN,46.9966,-95.0029,184.85.215.170
+US,SHEPHERDSVILLE,KY,37.9787,-85.6645,63.216.54.231
+TR,KAVACIK,"",41.48,27.90,23.74.24.69
+RU,NIZHNEKAMSK,"",55.64,51.82,2.21.240.40
+US,ANTIGO,WI,45.1268,-89.1724,23.74.8.8
+US,WESTBLOOMFIELD,MI,42.5418,-83.3806,184.84.180.68
+FR,ISSYLESMOULINEAUX,"",48.82,2.27,2.16.117.190
+LV,VENTSPILS,"",57.39,21.56,23.14.94.224
+US,RISINGSUN,MD,39.6875,-76.0358,209.48.37.183
+US,BARNARD,MO,40.1964,-94.7908,184.51.147.33
+UA,POLE,"",48.53,25.38,46.33.70.216
+FR,CASTELGINEST,"",43.70,1.43,2.16.117.200
+SE,KINNARP,O,58.07,13.52,213.155.156.207
+US,SCOTTSBURG,IN,38.6926,-85.8877,107.14.38.224
+US,IOLA,KS,37.9552,-95.4332,23.215.15.22
+PH,PASIG,"",14.58,121.08,23.76.205.111
+IR,GARMSAR,"",35.33,52.22,23.215.60.48
+US,BALLINGER,TX,31.7639,-99.8991,23.212.53.75
+US,AMBRIDGE,PA,40.6018,-80.2094,23.192.161.21
+FR,LESCAR,"",43.33,-0.42,2.16.117.190
+US,PROSPECTHEIGHTS,IL,42.1027,-87.9288,23.67.60.222
+US,SISSETON,SD,45.7041,-96.9842,23.79.255.153
+DE,WINTERBERG,NW,51.20,8.53,23.14.94.224
+US,RIOGRANDECITY,TX,26.5735,-98.695,184.26.93.116
+US,NORTHCHICAGO,IL,42.3271,-87.865,65.113.249.11
+US,ANNA,TX,33.3451,-96.5758,23.5.164.146
+US,WIMBERLEY,TX,30.0586,-98.15,23.61.195.160
+CA,STREETSVILLE,ON,43.58,-79.72,72.246.43.232
+JP,KOFU,19,35.65,138.58,117.104.139.162
+DE,HENSTEDTULZBURG,SH,53.78,10.00,2.20.142.166
+US,MINOA,NY,43.0745,-76.0083,107.14.38.224
+IT,PADOVA,"",45.42,11.88,193.45.15.198
+US,MONUMENT,CO,39.0574,-104.9038,184.84.180.68
+CZ,KLECANY,"",50.18,14.42,23.62.237.137
+US,FORTBELVOIR,VA,38.6990,-77.1368,184.28.17.76
+US,COHOES,NY,42.7824,-73.7303,107.14.38.217
+US,NYACK,NY,41.0938,-73.9254,69.31.77.208
+US,HOULTON,ME,46.1163,-67.9329,23.79.240.36
+US,CHANNELVIEW,TX,29.7912,-95.1165,96.17.163.165
+US,SILVERTHORNE,CO,39.7695,-106.1063,184.84.180.101
+NL,COEVORDEN,"",52.67,6.75,92.122.189.85
+VI,SAINTTHOMAS,"",18.3436,-64.9314,72.164.253.73
+RU,NIKOLSKOE,"",54.29,35.88,2.21.240.61
+US,MOUNTCARMEL,IL,38.4145,-87.8638,23.74.8.8
+US,RIPLEY,WV,38.8125,-81.6945,96.17.9.14
+US,STEVENSVILLE,MI,42.0039,-86.5132,23.67.60.220
+GB,BURNLEY,EN,53.80,-2.23,184.27.139.11
+US,CELINA,OH,40.5555,-84.6061,107.14.38.218
+RO,SIGHET,"",47.93,23.88,88.221.93.157
+AT,SANKTJOHANNAMWALDE,"",48.12,13.28,23.14.94.224
+ID,MANADO,"",1.48,124.85,23.0.162.21
+DE,MUENCHEBERG,BB,52.50,14.13,195.95.193.134
+US,KUTZTOWN,PA,40.5336,-75.7775,23.62.238.215
+TR,SAMSUN,"",41.28,36.33,193.45.15.198
+KZ,SULU,"",44.67,61.20,88.221.15.110
+VA,VATICANCITY,"",41.90,12.45,95.101.34.105
+PL,BORYSZEW,"",52.18,21.32,2.22.52.101
+KR,BUSAN,"",35.10,129.04,61.111.58.224
+FI,HAAPAJARVI,"",60.27,24.45,193.184.164.239
+US,EADS,TN,35.2015,-89.6087,184.84.180.68
+DE,KAMPE,NI,53.08,7.83,92.122.207.179
+DE,OGE,NW,51.32,7.52,195.95.193.134
+CA,SWIFTCURRENT,SK,50.28,-107.77,184.150.187.241
+US,CHASKA,MN,44.8087,-93.6418,23.210.5.166
+US,MALONE,NY,44.7347,-74.2672,107.14.38.224
+US,PEARSALL,TX,28.8736,-99.1074,107.14.43.30
+NO,SKJOLD,"",59.52,5.58,2.21.240.61
+US,BRECKENRIDGE,CO,39.4661,-106.0618,23.212.53.64
+US,DYSART,IA,42.1670,-92.3578,65.113.249.11
+PL,MARIA,"",50.17,18.77,2.22.52.105
+US,LOSLUNAS,NM,34.7465,-106.6041,184.84.180.92
+DE,HOHENSTEINERNSTTHAL,SN,50.80,12.72,2.20.142.166
+US,CRESTONE,CO,37.9964,-105.6994,23.215.15.9
+IR,GHAZVIN,"",35.60,47.02,23.215.60.48
+CA,IQALUIT,NU,63.73,-68.50,67.69.197.95
+US,GREENCITY,MO,40.2455,-92.9523,23.215.15.32
+US,MEDICINELODGE,KS,37.2282,-98.6992,208.35.28.213
+AT,PISCHELSDORF,"",48.00,16.57,195.145.147.107
+FR,MELUN,"",48.53,2.67,2.16.117.200
+US,STEPHENSCITY,VA,39.0680,-78.1954,23.192.161.16
+ES,GETAFE,"",40.30,-3.72,2.20.44.111
+CA,LAVAL,QC,45.60,-73.73,67.69.197.92
+FR,NANTUA,"",46.15,5.62,2.16.117.190
+US,BURKESVILLE,KY,36.7332,-85.3312,65.113.249.8
+RO,LUGOJ,"",45.68,21.90,81.196.26.236
+FR,HELLEMMES,"",50.62,3.12,2.16.117.190
+DE,BLOMBERG,NW,51.12,7.72,80.157.150.192
+US,ROCKFALLS,IL,41.7267,-89.7066,23.67.60.220
+NO,ELVERUM,"",60.88,11.57,217.212.227.31
+SK,BANSKABYSTRICA,"",48.73,19.15,23.62.237.138
+DE,VIERNHEIM,HE,49.54,8.58,23.14.94.224
+DE,FREITAL,SN,51.02,13.65,195.95.193.134
+SK,STUROVO,"",47.80,18.73,23.62.237.137
+AU,PENRITH,NSW,-33.75,150.70,104.72.70.96
+US,MORGANFIELD,KY,37.6418,-87.8654,107.14.38.224
+US,OAKVALE,WV,37.3344,-80.9628,184.27.45.157
+US,SIKESTON,MO,36.9406,-89.5948,23.63.227.223
+US,PITTSTON,PA,41.2973,-75.7399,23.77.238.9
+US,INGLESIDE,TX,27.8594,-97.2055,23.215.15.9
+SI,KRANJ,"",46.24,14.36,194.25.95.225
+FR,CLICHY,"",48.90,2.30,80.239.237.231
+IN,LANKA,CT,19.23,80.77,23.79.240.36
+RU,PETROPAVLOVSKKAMCHATSKIY,"",53.02,158.65,2.21.240.40
+IN,TIRUPATI,AP,13.65,79.42,23.57.69.159
+US,SOCORRO,NM,33.8946,-106.5652,63.226.34.172
+US,COLFAX,WA,46.8882,-117.4005,192.80.13.108
+IR,YASUJ,"",30.65,51.62,184.25.157.162
+IT,MONTALCINO,"",43.05,11.48,213.144.173.198
+US,MASHPEE,MA,41.6167,-70.4906,23.67.60.223
+US,RANSON,WV,39.3053,-77.8555,23.192.161.16
+US,BUSHNELL,FL,28.6844,-82.1562,184.51.35.226
+GB,RUNCORN,EN,53.33,-2.75,23.67.255.158
+US,WILLARD,OH,41.0531,-82.7265,23.220.148.108
+US,HEADLAND,AL,31.3604,-85.3205,63.151.29.15
+FR,MULHOUSE,"",47.75,7.33,2.16.117.200
+KR,PUSAN,"",35.10,129.04,23.65.188.30
+US,CRESSON,PA,40.4517,-78.5846,23.192.161.16
+JP,KASHIBA,29,34.55,135.70,23.3.104.20
+CN,LONGYOU,ZJ,29.03,119.17,72.246.191.19
+JP,NARITA,12,35.78,140.32,202.229.2.211
+US,DELAVAN,WI,42.6189,-88.608,184.85.215.165
+US,BOLTON,CT,41.7651,-72.4389,184.25.109.213
+US,WALKER,LA,30.5547,-90.828,23.215.15.9
+DE,GERMERING,BY,48.13,11.37,195.145.147.101
+JP,ICHIKAWA,12,35.72,139.93,96.7.251.95
+HU,KOSZEG,"",47.38,16.55,23.14.94.214
+DE,MERZ,BB,52.20,14.35,195.145.147.108
+NL,HILVARENBEEK,"",51.48,5.13,92.122.189.114
+US,WETHERSFIELD,CT,41.7005,-72.6721,23.212.53.75
+UA,SUMI,"",50.92,34.78,23.14.94.224
+FR,VILLEJUIF,"",48.80,2.37,2.16.117.190
+TR,KIBRIS,"",39.88,32.99,2.20.142.166
+FR,MODANE,"",45.20,6.67,2.16.117.190
+US,SODDYDAISY,TN,35.2876,-85.1755,23.61.195.150
+CZ,BYSTRICEPODHOSTYNEM,"",49.40,17.68,23.62.237.138
+FR,LACIOTAT,"",43.17,5.60,2.16.117.200
+AR,TORTUGUITAS,"",-34.47,-58.77,190.98.167.220
+US,network,CA,,,
+CN,SHANGQIU,HA,34.45,115.65,184.50.87.178
+US,CHANUTE,KS,37.6378,-95.4622,23.77.234.11
+CH,MURI,"",47.27,8.33,193.247.167.211
+PL,TYCHY,"",50.13,18.98,77.67.96.114
+US,SALINE,MI,42.1544,-83.8133,23.210.5.159
+FR,ANDREZIEUX,"",45.53,4.27,88.221.83.118
+US,GERALDINE,AL,34.3477,-86.0502,204.2.243.132
+US,QUARRYVILLE,PA,39.8731,-76.1426,23.192.161.21
+IN,CUDDAPAH,AP,14.47,78.82,23.205.118.106
+RU,PERESLAVLZALESSKIY,"",56.73,38.85,2.21.240.58
+PK,MULTAN,"",30.18,71.48,92.122.189.114
+AT,MATREIINOSTTIROL,"",47.00,12.53,195.145.147.107
+US,YOUNGTOWN,AZ,33.5903,-112.3029,63.226.34.176
+SI,SOSTANJ,"",46.38,15.05,84.53.175.90
+AT,NEUMARKT,"",48.13,15.05,88.221.93.157
+US,CORYDON,IN,38.1945,-86.1397,107.14.38.217
+US,GRIMES,IA,41.6833,-93.7869,23.67.60.217
+US,BONITA,CA,32.6730,-117.0021,63.151.119.16
+US,KNOBNOSTER,MO,38.6730,-93.5632,204.93.47.220
+DE,BERGHEIM,HE,50.35,9.08,80.157.170.158
+AR,LUISGUILLON,"",-34.80,-58.45,80.239.237.230
+RU,SOLNECHNOGORSK,"",56.18,36.98,213.155.156.207
+US,FORTTHOMAS,KY,39.0785,-84.4516,107.14.38.227
+DK,ESBJERG,"",55.47,8.45,23.65.29.93
+IN,AMALAPURAM,AP,16.58,82.02,23.57.69.156
+NG,ABUJA,"",9.25,6.93,23.212.108.8
+HN,SULACO,"",14.92,-87.27,72.246.65.37
+FI,TURKU,"",60.45,22.28,80.239.237.93
+KZ,ASYL,"",43.17,76.57,23.212.108.8
+US,INDIANOLA,IA,41.3316,-93.579,65.113.249.8
+IN,AGARPARA,WB,22.68,88.37,23.57.69.157
+US,MOREHEADCITY,NC,34.7367,-76.7587,209.18.41.27
+DE,HERBRECHTINGEN,BW,48.62,10.18,2.16.217.206
+GB,HERSHAM,EN,51.37,-0.40,23.67.255.158
+US,FREDERICKTOWN,MO,37.4979,-90.375,165.254.207.117
+IL,YAVNE,"",31.88,34.74,82.102.137.137
+US,LINCOLNCITY,OR,44.9454,-123.8611,184.27.179.187
+US,COOSBAY,OR,43.3057,-124.0564,184.27.179.187
+BY,STANTSIYA,"",53.61,30.22,80.239.222.190
+US,BAYARD,NM,32.6728,-108.0532,63.226.34.173
+US,VANALSTYNE,TX,33.4370,-96.5164,23.215.15.32
+US,KINGOFPRUSSIA,PA,40.0943,-75.3802,23.67.242.139
+US,SLATON,TX,33.4457,-101.6708,96.16.7.101
+FR,PLAISIR,"",48.82,1.95,2.16.117.190
+US,PISGAHFOREST,NC,35.2750,-82.6771,204.2.243.143
+US,CALISTOGA,CA,38.6394,-122.639,96.17.12.48
+FR,LEMANS,"",48.00,0.20,2.16.117.190
+US,CLARINDA,IA,40.7901,-95.0305,23.74.8.24
+MY,KINABALU,"",5.98,116.07,96.17.180.177
+AT,LEISACH,"",46.81,12.75,46.33.70.97
+IN,NANDED,MH,21.15,75.27,117.239.189.99
+IT,PIACENZA,"",45.02,9.67,2.18.240.95
+US,RAHWAY,NJ,40.6077,-74.2804,23.192.161.16
+MN,SUKHBAATAR,"",50.23,106.21,92.122.215.89
+BG,LOVECH,"",43.13,24.72,2.20.45.102
+NL,HAARLEM,"",52.37,4.65,92.122.189.85
+US,KINGSLAND,GA,30.8312,-81.764,63.234.249.61
+US,COLUMBIAFALLS,MT,48.4206,-114.1748,23.212.53.75
+US,TRAVELERSREST,SC,35.0688,-82.4166,72.246.247.5
+EE,JOE,"",59.43,24.58,213.155.156.212
+DE,HANSEN,NI,52.95,10.48,23.65.29.106
+IT,STEFANIA,"",44.38,11.45,193.45.15.199
+PR,VEGABAJA,"",18.4061,-66.3012,72.164.253.68
+IN,JODHPUR,RJ,26.29,73.03,96.17.182.130
+US,NEWULM,MN,44.2563,-94.471,23.67.60.220
+NL,GRONINGEN,"",53.22,6.55,2.20.243.45
+US,NEILLSVILLE,WI,44.5294,-90.6622,23.74.8.8
+NL,EERSEL,"",51.37,5.32,95.101.2.113
+NL,ARNHEM,"",51.98,5.92,2.16.153.173
+US,SYLVA,NC,35.3551,-83.1997,184.51.35.226
+SE,SKELLEFTEA,AC,64.77,20.95,2.21.240.61
+PL,LOWCE,"",49.93,22.73,80.15.235.171
+US,UNDERWOOD,MN,46.3249,-95.8405,23.74.8.8
+US,MOULTON,AL,34.4578,-87.2911,23.212.53.75
+NG,AUN,"",8.33,5.33,77.67.41.223
+US,NEVADACITY,CA,39.3517,-120.851,23.61.195.163
+UZ,NAMANGAN,"",41.00,71.67,2.21.240.61
+US,SOUTHPADREISLAND,TX,26.3706,-97.228,23.5.164.146
+IN,GOREGAON,MH,18.17,73.30,23.211.135.66
+US,GLENOLDEN,PA,39.9030,-75.2932,23.67.242.139
+US,ELBERTON,GA,34.1050,-82.81,23.79.240.36
+US,LARKSPUR,CO,39.1989,-104.8931,23.215.15.9
+AR,MARDEAJO,"",-36.72,-56.67,200.123.201.215
+IT,ASCOLIPICENO,"",42.85,13.57,2.18.240.95
+US,BERWICK,PA,41.0944,-76.241,165.254.48.142
+US,PASCAGOULA,MS,30.5698,-88.4248,24.143.197.206
+CH,LUCERNE,"",47.08,8.27,193.247.167.211
+US,PONCHATOULA,LA,30.4008,-90.3723,23.79.240.48
+US,MARFA,TX,30.1759,-104.2916,96.17.163.161
+US,IRONTON,OH,38.5450,-82.6629,96.17.9.8
+RU,BERYOZOVSKY,"",54.03,120.17,2.21.240.40
+RS,ZRENJANIN,"",45.38,20.38,2.20.45.104
+PT,MOITA,"",38.65,-8.98,195.22.14.133
+FR,SARTROUVILLE,"",48.95,2.18,2.16.117.190
+US,MARBLEFALLS,TX,30.5925,-98.2219,23.215.15.9
+ID,CIKUPA,"",-6.23,106.52,23.0.162.40
+CZ,UPICE,"",50.52,16.02,23.62.237.137
+IN,SILCHAR,AS,24.82,92.80,124.124.40.95
+JP,CHOFU,13,35.66,139.55,72.246.191.19
+IN,UJJAIN,MP,23.18,75.77,117.239.189.111
+GB,ROCHDALE,EN,53.62,-2.15,23.67.255.158
+US,EDENTON,NC,36.1056,-76.6017,96.16.12.228
+FR,FONTAINE,"",48.35,2.15,2.16.117.190
+US,WYTHEVILLE,VA,36.9511,-81.112,184.29.107.38
+EC,BABAHOYO,"",-1.82,-79.52,72.246.65.23
+IN,SANGRUR,PB,30.23,75.83,96.17.182.130
+FI,JOENSUU,"",62.60,29.77,2.21.240.40
+SA,JAZAN,"",16.89,42.55,46.33.70.216
+US,CANEY,KS,37.0586,-95.8808,69.31.59.73
+DE,ROS,BY,49.25,10.55,195.95.193.132
+AT,JERZENS,"",47.15,10.73,46.33.70.97
+US,METAMORA,IL,40.7942,-89.4075,23.79.240.36
+US,CHICOPEE,MA,42.1705,-72.6067,63.141.200.248
+US,CLEWISTON,FL,26.4660,-80.9492,23.79.240.48
+BN,SERIA,"",4.62,114.32,96.17.180.177
+US,VERADALE,WA,47.6287,-117.1938,23.212.59.85
+RU,NOGINSKAYA,"",60.78,42.68,63.216.54.236
+US,CIRCLE,MT,47.4646,-105.835,184.51.35.226
+NL,ALMELO,"",52.35,6.67,92.122.189.114
+IT,MARINO,"",42.83,13.65,46.33.73.225
+CN,DEYANG,SC,31.13,104.40,23.15.10.106
+CH,LANGENTHAL,"",47.22,7.78,193.247.167.211
+FR,ANGOULEME,"",45.65,0.15,2.16.117.200
+US,BARDSTOWN,KY,37.7964,-85.4724,107.14.38.227
+US,MUSCATINE,IA,41.4340,-91.0853,205.185.195.183
+PL,SIEMIANOWICESLASKIE,"",50.30,19.03,80.157.149.181
+IN,TIRUCHCHIRAPPALLI,TN,10.80,78.69,80.239.237.231
+US,EASTSAINTLOUIS,IL,38.6386,-90.1321,204.93.47.216
+US,PROCTORVILLE,OH,38.4900,-82.3527,23.212.53.75
+CZ,PROSTEJOV,"",49.47,17.12,23.62.237.133
+US,OAKTON,VA,38.8902,-77.3289,23.220.148.122
+HU,TATA,"",47.65,18.32,92.122.189.85
+US,HAZELCREST,IL,41.5748,-87.6813,23.67.60.220
+FR,VILLEFRANCHESURMER,"",43.70,7.32,2.16.117.200
+HU,BECSEHELY,"",46.45,16.80,195.145.147.107
+BG,PLEVEN,"",43.42,24.62,2.20.142.166
+US,MINOOKA,IL,41.4851,-88.3207,107.14.38.227
+US,FESTUS,MO,38.1363,-90.407,23.79.255.153
+ID,CENGKARENG,"",-6.15,106.72,2.22.52.102
+TH,CHIANGMAI,"",18.79,98.98,61.19.12.176
+US,NEWSTANTON,PA,40.2329,-79.6397,209.48.37.188
+US,WEEHAWKEN,NJ,40.7678,-74.0275,184.51.35.226
+US,WENONAH,NJ,39.7966,-75.1429,184.26.44.38
+US,MAYSVILLE,KY,38.5850,-83.7789,23.79.240.48
+SK,TRNAVA,"",48.37,17.60,92.122.215.67
+RU,DZERZHINSKIY,"",55.63,37.84,80.239.237.80
+US,WELCH,WV,37.3787,-81.5098,23.74.8.8
+FR,BEAUZELLE,"",43.67,1.37,2.16.117.190
+AT,GRIESKIRCHEN,"",48.23,13.83,195.145.147.109
+US,COPPEROPOLIS,CA,37.9530,-120.6995,173.223.52.70
+AR,DELVISO,"",-34.45,-58.80,190.98.167.230
+GB,GREATYARMOUTH,EN,52.63,1.75,23.67.255.158
+US,BONHAM,TX,33.5544,-96.2,23.215.15.9
+US,LAGRANGEPARK,IL,41.8338,-87.8701,23.67.60.217
+IT,SALUZZO,"",44.65,7.48,2.18.240.114
+DE,BADOLDESLOE,SH,53.82,10.38,92.122.207.179
+CA,SAINTJEAN,QC,45.30,-73.25,67.69.197.95
+CA,LORETTEVILLE,QC,46.85,-71.37,165.254.96.242
+AT,FUSSACH,"",47.48,9.67,84.53.146.34
+US,PENNSGROVE,NJ,39.6981,-75.4502,23.67.242.139
+FR,MARTIGNASSURJALLE,"",44.83,-0.77,2.16.117.200
+FR,LERAINCY,"",48.90,2.52,2.16.117.190
+US,NEWCANEY,TX,30.1594,-95.1973,96.17.163.165
+AT,EDT,"",47.87,14.68,195.145.147.108
+US,NATRONAHEIGHTS,PA,40.6420,-79.7309,65.121.209.141
+US,POPLARVILLE,MS,30.8781,-89.5858,96.17.153.157
+KR,SANGJU,"",36.41,128.15,61.111.58.229
+DE,CELLE,NI,52.62,10.08,195.245.125.114
+US,CENTER,TX,31.7586,-94.1975,64.145.68.38
+US,APOLLO,PA,40.5292,-79.5952,23.192.161.16
+US,TEANECK,NJ,40.8902,-74.0104,63.238.85.169
+AR,RAMALLO,"",-33.48,-60.02,200.123.201.215
+PL,KONIN,"",51.70,19.28,2.22.61.102
+PR,FAJARDO,"",18.3304,-65.6573,23.74.2.7
+US,PUNXSUTAWNEY,PA,40.9472,-78.981,23.67.242.156
+PL,GLOGOW,"",51.42,20.87,2.22.52.109
+US,NORTHBRANCH,MN,45.5343,-92.8964,107.14.38.217
+RU,NOYABRSK,"",63.17,75.62,2.21.240.40
+US,ZELIENOPLE,PA,40.7632,-80.1242,65.121.209.133
+RU,ALTAISK,"",51.96,85.35,80.239.237.80
+IR,ASHENA,"",36.45,49.98,184.27.45.150
+US,MARS,PA,40.7051,-80.0184,72.246.52.107
+ZA,GREENPOINT,"",-33.92,18.40,165.165.46.36
+US,BURNHAM,PA,40.6380,-77.5634,23.67.242.139
+RU,ZELENOGRAD,"",56.00,37.21,80.239.237.93
+US,WOODLANDPARK,CO,39.0237,-105.0999,23.212.53.75
+US,VALLEYCOTTAGE,NY,41.1240,-73.9363,184.51.125.79
+FR,BOURGES,"",47.08,2.40,2.16.117.200
+US,FORRESTCITY,AR,35.0264,-90.8596,23.220.100.223
+US,SANDERSVILLE,GA,33.0015,-82.8994,23.79.240.36
+SE,HALMSTAD,N,56.67,12.86,2.21.240.40
+CZ,BROD,"",49.67,14.02,23.62.237.133
+RO,COVASNA,"",45.85,26.18,2.22.52.105
+US,MIDDLESBORO,KY,36.6372,-83.7049,107.14.38.227
+US,BEND,OR,44.1187,-121.282,67.131.104.14
+SK,SKALITE,"",49.50,18.90,23.62.237.135
+US,UNIONBRIDGE,MD,39.5440,-77.1891,23.215.15.22
+PL,RAWAMAZOWIECKA,"",51.77,20.25,80.239.149.123
+HU,MISKOLC,"",48.10,20.78,23.14.94.228
+US,EMMETSBURG,IA,43.0838,-94.6785,165.254.207.111
+FR,JANZE,"",47.97,-1.50,2.16.117.190
+IN,WASHIM,MH,20.10,77.15,23.205.118.109
+US,WESTHELENA,AR,34.5741,-90.6745,23.5.164.143
+US,MARYESTHER,FL,30.4108,-86.7601,165.254.45.32
+CZ,BOSKOVICE,"",49.48,16.67,23.62.237.133
+BD,MIRPUR,"",23.57,90.62,23.57.76.18
+SS,JUBA,"",4.85,31.60,41.193.163.53
+US,CLAY,NY,43.1873,-76.1924,107.14.38.217
+US,BLACKFOOT,ID,43.2718,-112.4055,206.104.149.146
+RU,IGRA,"",57.56,53.05,2.21.240.61
+US,ROGERSVILLE,AL,34.8568,-87.316,23.220.100.223
+IN,GHATKOPAR,MH,19.08,72.90,23.14.94.214
+BG,GABROVO,"",42.62,25.17,92.122.188.161
+US,CHESTNUTHILL,MA,42.3163,-71.1603,107.14.32.235
+DE,PLAN,SN,50.93,14.13,80.157.150.201
+BD,FENI,"",23.00,91.40,96.17.180.177
+US,WEBBCITY,MO,37.1493,-94.4792,107.14.43.30
+FR,MONTFERMEIL,"",48.90,2.57,2.16.117.200
+US,RIPON,WI,43.8527,-88.8455,23.63.227.227
+FR,MONTIVILLIERS,"",49.55,0.20,88.221.15.110
+CZ,ZABREH,"",49.88,16.87,23.62.237.135
+AR,MARIANOACOSTA,"",-34.73,-58.79,190.98.167.230
+US,WATERVILLE,OH,41.4970,-83.7598,107.14.38.227
+AT,KIRCHBERGINTIROL,"",47.45,12.32,195.145.147.108
+ID,PRABUMULIH,"",-3.45,104.25,23.0.162.46
+UA,KURILOV,"",50.55,34.72,23.14.94.224
+RU,OBNINSK,"",55.10,36.61,80.239.222.167
+US,SEAGOVILLE,TX,32.6388,-96.5631,184.28.23.24
+US,CAVECREEK,AZ,33.8319,-111.9436,63.226.34.181
+US,BULLSGAP,TN,36.3360,-83.0112,23.79.240.48
+RU,NAROFOMINSK,"",55.39,36.74,2.21.240.40
+BG,KASPICHAN,"",43.32,27.17,95.101.34.105
+US,ATTLEBORO,MA,41.9304,-71.2954,23.192.161.21
+US,ROCKMART,GA,33.9615,-85.0722,23.79.240.48
+IR,BANK,"",27.87,52.03,23.62.238.215
+AU,NEWRYBAR,NSW,-28.72,153.53,104.72.70.95
+US,MCPHERSON,KS,38.4089,-97.6556,174.76.226.110
+SE,OREBRO,T,59.28,15.22,23.60.69.210
+UA,DRUZHKOVKA,"",48.62,37.55,23.14.94.228
+US,DEMOTTE,IN,41.1657,-87.2663,23.74.8.24
+GB,FLEET,EN,51.28,-0.83,23.67.71.116
+JP,TAKAYAMA,21,36.13,137.25,23.61.250.108
+AR,HUINCARENANCO,"",-34.83,-64.38,200.123.201.215
+FI,LOVIISA,"",60.45,26.23,2.21.240.40
+US,SNEADS,FL,30.7730,-84.9746,63.151.29.15
+US,CUBA,MO,38.1231,-91.4205,204.93.47.216
+GB,ENFIELD,EN,51.67,-0.07,23.3.15.11
+US,MAGEE,MS,31.8220,-89.7913,96.17.153.157
+PH,ILOILO,"",10.70,122.57,63.217.232.22
+SE,LINKOPING,E,58.42,15.62,2.21.240.40
+GR,XANTHI,"",41.13,24.88,23.14.94.214
+JP,NOMURA,36,34.05,134.10,118.155.230.132
+US,DECORAH,IA,43.3626,-91.8164,107.14.38.224
+IR,SENA,"",29.22,51.59,96.17.182.136
+RO,STEFANESTI,"",44.52,26.73,81.196.26.237
+US,MANTEO,NC,35.8834,-75.6616,184.28.127.58
+FR,EPINAYSURSEINE,"",48.95,2.32,2.16.117.200
+US,DALLASTOWN,PA,39.8950,-76.6501,23.192.161.16
+US,FORTDRUM,NY,44.1255,-75.6043,107.14.38.224
+LY,BENGHAZI,"",32.12,20.07,79.140.94.243
+US,SCHNECKSVILLE,PA,40.6716,-75.6276,184.26.44.38
+MY,KOTA,"",2.52,102.17,58.27.124.241
+BG,PANCHAREVO,"",42.60,23.42,2.20.142.173
+PL,SZCZYTNO,"",52.25,20.35,80.239.222.167
+US,KAUFMAN,TX,32.5074,-96.2414,23.212.53.64
+MY,PETALINGJAYA,"",3.08,101.65,58.26.185.142
+US,STUARTSDRAFT,VA,37.9955,-79.0396,184.27.45.157
+US,WHITESBORO,TX,33.6662,-96.8486,23.5.164.143
+US,KILLDEVILHILLS,NC,36.0144,-75.6824,23.79.240.48
+ES,ABI,"",42.47,0.43,90.84.53.193
+CZ,SEBROV,"",49.33,16.60,23.62.237.133
+RU,USSURIYSK,"",43.80,131.98,72.246.184.81
+US,CENTERVALLEY,PA,40.5452,-75.4231,184.27.45.157
+US,LAKEMARY,FL,28.7595,-81.3431,184.51.145.22
+US,DELMAR,CA,32.9697,-117.2461,63.151.119.16
+NL,DINXPERLO,"",51.87,6.48,92.122.189.114
+US,ROSELAND,NJ,40.8207,-74.3087,72.246.247.5
+PL,CZESTOCHOWA,"",50.80,19.12,80.239.222.169
+US,POLLOCKPINES,CA,38.7953,-120.4833,165.254.144.25
+US,HOLDREGE,NE,40.4958,-99.3198,65.113.249.8
+US,MERRILLVILLE,IN,41.4814,-87.338,23.67.60.220
+US,HUNTINGBURG,IN,38.3038,-86.9615,165.254.207.111
+US,EASTELMHURST,NY,40.7630,-73.8708,24.143.199.156
+US,MANNFORD,OK,36.0666,-96.3642,64.129.104.132
+DE,LAUF,BY,50.00,10.95,84.53.146.39
+RU,KLIMOVSK,"",61.28,53.63,80.239.237.93
+CZ,LOSAN,"",50.40,13.52,23.62.237.133
+DE,RADOLFZELL,BW,47.73,8.97,2.20.142.166
+IT,ANTEA,"",45.85,9.67,2.18.240.95
+CR,LIBERIA,"",10.63,-85.43,72.164.253.83
+US,ELIZABETHTON,TN,36.4118,-82.0968,184.29.107.20
+JP,SAGA,41,33.25,130.30,117.104.139.136
+US,BREVARD,NC,35.2304,-82.7632,184.51.35.226
+US,GALATIA,IL,37.8301,-88.6284,107.14.38.217
+US,GATECITY,VA,36.6668,-82.6167,64.86.201.121
+DE,DUREN,NW,50.80,6.48,23.14.94.228
+US,SHEBOYGANFALLS,WI,43.7266,-87.8486,184.85.215.165
+US,BUNKIE,LA,30.9328,-92.1876,96.17.153.157
+US,SAUKCITY,WI,43.2637,-89.8631,184.85.215.165
+IT,QUADRI,"",41.92,14.28,95.101.34.105
+BG,KAZANLAK,"",42.62,25.40,2.20.142.173
+IT,LADISPOLI,"",41.93,12.08,46.33.70.216
+PH,CAFE,"",15.32,120.70,58.71.107.120
+DE,KANZLEI,NW,51.25,6.68,80.157.170.158
+US,EASTROCHESTER,NY,43.1125,-77.4905,107.14.38.227
+IR,SHARIF,"",34.07,48.08,80.15.235.161
+FR,CANNES,"",43.55,7.02,2.16.117.200
+US,FRUITA,CO,39.2686,-108.68,63.235.21.147
+MT,SLIEMA,"",35.91,14.50,23.14.94.220
+US,HINCKLEY,OH,41.2388,-81.7346,107.14.38.224
+FR,RILLIEUX,"",45.82,4.90,90.84.50.115
+NL,LISSE,"",52.25,4.57,92.122.189.114
+DE,ENG,BY,48.85,12.80,80.157.170.231
+TH,KOH,"",18.82,101.05,180.180.251.220
+US,WORLAND,WY,43.9271,-107.8134,205.185.195.183
+US,OTISORCHARDS,WA,47.6956,-117.1108,67.131.104.14
+US,MIDDLEBORO,MA,41.8934,-70.9117,184.25.109.213
+US,MAUMEE,OH,41.5735,-83.6863,65.113.249.11
+US,MCRAE,GA,31.9833,-82.8682,63.216.54.229
+US,TRUMANN,AR,35.6187,-90.5393,173.197.194.159
+IN,NARAINA,RJ,26.78,75.20,96.17.182.130
+CZ,BORKOVANY,"",49.03,16.82,23.74.24.69
+FR,MONTARGIS,"",48.00,2.75,2.16.117.190
+CZ,HRADECKRALOVE,"",50.21,15.84,23.62.237.138
+SE,MALA,M,56.23,13.70,2.21.240.58
+DE,BENSHEIM,HE,49.68,8.62,77.67.27.250
+US,CASTLEHAYNE,NC,34.3390,-77.8941,184.27.45.150
+US,WOODSCROSS,UT,40.8888,-111.9281,23.61.195.165
+KR,ANSAN,"",37.32,126.82,61.111.58.43
+US,LAURINBURG,NC,34.7588,-79.4468,209.18.41.27
+JP,HACHIOJI,13,35.66,139.33,72.246.184.89
+US,MELVINDALE,MI,42.2809,-83.178,23.67.60.217
+US,KEENE,NH,42.9764,-72.2744,107.14.38.217
+US,NORTHMYRTLEBEACH,SC,33.8371,-78.6471,184.51.35.226
+US,CEDARBURG,WI,43.3081,-88.0364,65.113.249.8
+GB,SELLING,EN,51.27,0.92,77.67.27.235
+FR,SAINTJULIENENGENEVOIS,"",46.13,6.08,2.16.117.190
+FR,METZ,"",49.13,6.17,88.221.15.110
+US,HIGHSPRINGS,FL,29.8528,-82.6553,23.33.186.101
+US,JUNCTIONCITY,KS,38.9467,-96.7996,174.76.226.117
+US,MUNCY,PA,41.2250,-76.7388,63.216.54.236
+BR,NOVOHAMBURGO,RS,-29.68,-51.13,187.59.4.154
+IT,DESENZANODELGARDA,"",45.47,10.53,195.22.200.240
+US,BEALETON,VA,38.5752,-77.8213,23.192.161.21
+BR,ARACAJU,SE,-10.92,-37.07,200.216.8.59
+PL,CIECHOCINEK,"",52.87,18.80,80.239.222.190
+ID,BADUNG,"",-7.57,112.50,96.17.180.166
+JP,ISUZU,17,37.33,136.73,23.15.1.67
+ES,ARNEDO,"",42.22,-2.10,92.123.73.26
+US,VIVIAN,LA,32.8582,-93.9626,23.212.53.64
+US,SCOBEY,MT,48.7328,-105.3949,184.27.179.187
+FI,KUOPIO,"",62.90,27.68,193.184.164.238
+JP,TSUSHIMA,23,35.17,136.72,23.3.104.15
+US,WINAMAC,IN,41.0563,-86.6606,205.185.195.170
+PL,RADOM,"",51.42,21.15,95.101.2.112
+IR,GILAN,"",33.11,49.61,23.14.94.224
+NL,LEUR,"",51.82,5.70,92.122.189.114
+ME,CRNAGORA,"",43.22,19.01,23.14.94.214
+CF,BANGUI,"",4.37,18.58,95.101.34.105
+ID,SAMPIT,"",-2.53,112.95,23.0.162.21
+DE,KREISCHA,SN,51.28,13.10,195.95.193.147
+US,CAROLINABEACH,NC,34.0370,-77.9026,184.28.127.58
+MY,IPOH,"",4.58,101.08,63.233.61.159
+NL,NAALDWIJK,"",52.00,4.20,92.122.189.85
+PL,PODLASIE,"",51.93,17.95,2.22.52.109
+AT,MICHAEL,"",47.13,16.27,195.145.147.101
+US,LAVONIA,GA,34.4474,-83.1313,63.216.54.236
+US,RUSHVILLE,IN,39.6183,-85.4164,23.67.60.222
+IN,GULBARGA,KA,17.33,76.83,117.239.240.76
+US,ABERCROMBIE,ND,46.4479,-96.7302,23.79.255.153
+US,WENTZVILLE,MO,38.7993,-90.8471,204.93.47.220
+DE,PLAUEN,SN,50.50,12.13,80.157.150.192
+PL,GOSTYNIN,"",52.43,19.48,80.157.149.181
+EE,KURESSAARE,"",58.24,25.81,213.155.156.206
+RU,NADYM,"",65.53,72.52,92.122.215.89
+TR,ESKISEHIR,"",39.77,30.53,193.45.15.199
+DE,STRELITZ,MV,53.33,13.10,80.157.170.231
+FR,CREIL,"",49.27,2.48,2.16.117.190
+DE,NIEFERN,BW,48.92,8.78,23.14.94.220
+RU,UGRA,"",54.50,36.12,80.239.222.167
+US,STRATFORD,IA,42.2953,-93.8747,165.254.114.198
+US,BENNINGTON,VT,42.9148,-73.1152,107.14.38.217
+PH,LOPEZ,"",13.88,122.25,58.71.107.119
+JP,MATSUE,32,35.47,133.07,117.104.139.136
+US,SUGARGROVE,IL,41.7828,-88.4458,23.67.60.220
+CO,IPIALES,"",0.83,-77.62,200.14.44.103
+US,DELAFIELD,WI,43.0452,-88.3996,107.14.38.218
+NG,KANO,"",12.00,8.52,92.123.73.233
+FR,VAULXENVELIN,"",45.78,4.93,2.16.117.190
+MY,BADAK,"",6.48,100.57,203.106.85.4
+US,OLYMPICVALLEY,CA,38.9090,-121.0703,65.113.249.11
+SE,SKONDAL,AB,59.25,18.12,82.96.58.102
+US,BLANDON,PA,40.4457,-75.8746,165.254.48.154
+BE,LEUVEN,"",50.88,4.70,95.101.2.112
+US,IVYDALE,WV,38.5245,-81.029,23.74.8.8
+US,RAYNHAM,MA,41.9389,-71.0535,23.67.60.220
+US,HOPEWELL,VA,37.2760,-77.217,184.27.45.150
+US,APOLLOBEACH,FL,27.7623,-82.3865,192.204.82.221
+FR,CRETEIL,"",48.78,2.47,92.122.189.85
+DE,BIBERACH,BW,49.19,9.14,23.14.94.228
+PL,LESZNO,"",52.27,20.60,2.22.61.99
+YT,DZAOUDZI,"",-12.78,45.25,2.20.243.42
+RU,NIZHNIYNOVGOROD,"",56.33,44.00,217.212.227.25
+US,BOULDERCITY,NV,35.9098,-114.7587,165.254.144.32
+US,COLUMBIANA,OH,40.8786,-80.6854,23.192.161.16
+HN,SANPEDROSULA,"",15.50,-88.03,23.74.2.7
+US,BACLIFF,TX,29.5051,-94.9907,23.212.53.64
+RU,CHAPLYGIN,"",45.11,40.76,80.239.222.169
+CN,HENGYANG,HN,26.97,112.60,72.246.191.19
+US,GARRETTSVILLE,OH,41.3076,-81.0739,65.113.249.8
+DE,JULICH,NW,50.93,6.37,23.14.94.220
+US,MOORESTOWN,NJ,39.9782,-74.9415,184.26.44.42
+US,ROUNDHILL,VA,39.1007,-77.7961,96.6.47.106
+DE,MITTWALD,NW,52.38,8.63,92.122.207.179
+PL,GNIEZNO,"",52.55,17.60,23.14.94.228
+CN,WUXING,ZJ,30.87,120.10,72.246.191.16
+TR,ICEL,"",36.80,34.63,92.122.188.163
+FR,VIGNEUXSURSEINE,"",48.70,2.42,2.16.117.190
+US,CASSOPOLIS,MI,41.8990,-85.985,72.247.10.241
+IN,RAJPURA,PB,30.48,76.59,23.205.118.106
+ES,RIOJA,"",36.95,-2.45,92.122.188.163
+ID,PURWOKERTO,"",-7.42,109.23,23.0.162.46
+US,GRINNELL,IA,41.7319,-92.7662,23.74.8.24
+ES,ISLAS,"",43.37,-2.67,213.248.113.93
+US,MURPHYSBORO,IL,37.7760,-89.3234,23.74.8.24
+RU,BIZ,"",57.26,58.64,2.22.52.102
+FO,HOYVIK,"",62.03,-6.75,92.122.127.109
+FR,LETOUVET,"",45.35,5.95,2.16.117.200
+JP,MORI,22,34.83,137.93,23.15.1.29
+ID,LOMBOK,"",-8.50,116.67,23.0.162.21
+FR,ARGENTEUIL,"",48.95,2.25,2.16.117.190
+CN,SANYA,HI,18.24,109.50,184.50.87.176
+US,CORONADELMAR,CA,33.6005,-117.8539,184.50.26.204
+CH,DELEMONT,"",47.37,7.33,213.254.212.77
+US,WOODLAND,WA,45.9549,-122.6998,23.212.59.85
+RU,BALAKOVO,"",52.03,47.78,2.21.240.40
+FR,LAFRANCE,"",46.03,5.13,81.52.201.97
+DE,WADERN,SL,49.53,6.88,92.122.215.67
+US,LONGS,SC,33.8946,-78.7949,209.18.41.23
+US,ORANGEBEACH,AL,30.2789,-87.6082,72.246.247.30
+PK,MAIL,"",32.55,71.62,96.17.182.130
+US,HERINGTON,KS,38.7322,-97.0904,23.215.15.9
+PL,BIELANYWROCLAWSKIE,"",51.03,16.97,2.22.61.102
+FR,COLMAR,"",48.08,7.37,2.16.117.190
+CA,SAINTJEROME,QC,45.77,-74.00,67.69.197.160
+VN,HAIPHONG,"",20.87,106.68,23.76.205.111
+PL,INOWROCLAW,"",52.80,18.27,80.239.149.123
+CZ,PRIBRAM,"",49.70,14.02,23.62.237.135
+TR,GEBZE,"",40.80,29.42,79.140.94.183
+US,SANTAROSABEACH,FL,30.3512,-86.1547,184.51.35.215
+HU,PECS,"",46.08,18.23,80.239.237.231
+US,HUBERT,NC,34.6594,-77.2628,209.18.41.23
+NZ,KERIKERI,"",-35.22,173.97,219.88.186.167
+CZ,SVITAVKA,"",49.50,16.60,23.62.237.135
+UA,DNEPRODZERZHINSK,"",48.50,34.62,23.14.94.228
+PL,JASLO,"",49.75,21.47,2.22.52.105
+US,DEFUNIAKSPRINGS,FL,30.7313,-86.1987,184.51.35.226
+US,WHEELERSBURG,OH,38.7507,-82.7819,107.14.38.227
+US,WORTH,IL,41.6850,-87.7773,107.14.38.227
+US,PLATTECITY,MO,39.3588,-94.8136,209.170.117.169
+IN,NAVSARI,GJ,20.85,72.92,96.17.182.136
+AU,COFFSHARBOUR,NSW,-30.30,153.13,202.7.177.76
+US,COLLINS,MS,31.6692,-89.543,96.17.153.157
+DE,KNICK,NI,53.25,9.73,194.25.95.214
+US,BROWNSMILLS,NJ,39.9516,-74.5548,184.26.44.42
+NL,VEN,"",51.63,5.55,95.101.2.122
+RO,ORSOVA,"",46.75,24.90,81.196.26.236
+US,PROSSER,WA,46.3675,-119.7188,67.131.104.6
+TR,ESENTEPE,"",40.82,30.80,23.63.227.214
+US,SCHWENKSVILLE,PA,40.2583,-75.5011,23.67.242.156
+US,ROSCOE,IL,42.4315,-88.9848,184.85.215.165
+US,SOPHIA,WV,37.6919,-81.2784,184.28.17.55
+AU,HAWTHORN,VIC,-37.83,145.03,61.9.129.199
+US,BEGGS,OK,35.7942,-96.0408,173.197.194.166
+UA,RIVNE,"",48.25,31.75,2.22.52.102
+AT,REITH,"",48.10,15.63,195.145.147.109
+CZ,CESKEBUDEJOVICE,"",48.98,14.47,23.62.237.138
+SK,SURANY,"",48.08,18.18,23.62.237.133
+NZ,MIRAMAR,"",-41.32,174.82,184.28.126.8
+ID,PEKANBARU,"",0.53,101.45,124.155.222.130
+PL,KROSNO,"",51.17,19.68,80.157.149.129
+DE,EHRLICH,RP,50.70,7.75,23.14.94.228
+US,HARLEYSVILLE,PA,40.2685,-75.3957,184.26.44.42
+IT,MARCHE,"",45.90,11.90,193.45.15.198
+AT,AUEN,"",46.88,14.82,195.145.147.107
+DE,HELLWEG,NW,51.53,7.73,2.20.142.173
+ID,CAWANG,"",-6.25,106.87,23.0.162.46
+AT,ISCHGL,"",47.02,10.28,195.145.147.101
+US,TELLCITY,IN,38.0217,-86.7099,23.79.240.36
+SK,SNINA,"",48.98,22.15,23.62.237.137
+CA,LISTOWEL,ON,43.73,-80.97,72.246.43.233
+US,HAMPDEN,ME,44.7323,-68.9137,165.254.35.197
+US,HAPPYVALLEY,OR,45.4104,-122.5055,23.212.59.63
+HU,HARKANY,"",45.85,18.24,23.14.94.228
+VE,MARACAY,"",10.25,-67.60,72.246.65.26
+AQ,MCMURDO,"",-77.80,166.70,63.226.34.176
+US,SOMERSWORTH,NH,43.2536,-70.8856,23.192.161.16
+IN,KANGRA,HP,32.10,76.27,117.239.189.110
+US,DYER,IN,41.4630,-87.5082,107.14.38.217
+RO,SIMERIA,"",45.85,23.02,81.196.26.236
+PL,SWIETOCHLOWICE,"",50.28,18.92,2.22.52.102
+US,HAZELPARK,MI,42.4623,-83.0976,107.14.38.224
+US,ROCKISLAND,IL,41.4874,-90.5678,23.77.234.35
+UA,PERVOMAYSK,"",48.05,30.85,217.212.227.31
+PS,NABLUS,"",32.22,35.25,2.20.142.166
+US,BUZZARDSBAY,MA,41.7705,-70.5815,184.25.109.196
+TR,DUZCE,"",40.83,31.17,193.45.15.199
+US,ROMEO,MI,42.8454,-83.0393,23.67.60.217
+US,PICKWICKDAM,TN,35.0531,-88.2379,69.31.59.63
+US,NEBRASKACITY,NE,40.6534,-95.8738,107.14.43.29
+RU,VLADIMIRSKAYA,"",55.67,33.29,80.239.237.99
+NL,ZWOLLE,"",52.50,6.08,92.122.189.114
+US,LONGVALLEY,NJ,40.7842,-74.79,184.26.44.38
+AT,WAIDHOFENANDERYBBS,"",47.97,14.77,23.62.237.138
+FR,SAINTETIENNE,"",45.43,4.40,2.16.117.200
+FR,VALENCIENNES,"",50.35,3.53,2.16.117.200
+AT,SEEBODEN,"",46.82,13.49,195.145.147.107
+US,IRVINGTON,NJ,40.7242,-74.2319,23.67.242.139
+NL,HENGELO,"",52.27,6.80,92.122.189.114
+US,LEDGEWOOD,NJ,40.8749,-74.6666,72.247.10.241
+US,BRANFORD,CT,41.2857,-72.7978,184.25.109.200
+US,ARKADELPHIA,AR,34.0941,-93.0475,23.5.164.143
+JP,CHITOSE,01,42.82,141.65,72.246.184.89
+FI,LAUTTASAARI,"",60.16,24.87,82.96.58.85
+IT,SOLIGO,"",45.91,12.15,2.18.240.114
+JP,KAMAKURA,14,35.31,139.55,72.246.184.89
+AR,SANANDRES,"",-34.55,-58.53,80.239.237.231
+US,ANGLETON,TX,29.1898,-95.4754,96.17.163.165
+CA,CARP,ON,45.35,-76.03,67.231.211.247
+CN,MEIZHOU,GD,24.33,116.12,80.239.237.231
+US,PAGE,AZ,36.8282,-111.1539,65.116.149.89
+IN,ELURU,AP,16.70,81.10,124.124.201.221
+HT,DELMAS,"",18.54,-72.30,23.74.2.7
+US,THATCHER,AZ,32.7621,-109.8381,65.116.149.102
+CA,LAKELOUISE,AB,51.43,-116.18,24.244.17.197
+CN,KUITUN,XJ,44.42,85.00,80.239.237.230
+US,MONMOUTHJUNCTION,NJ,40.3897,-74.5487,124.155.222.130
+US,PEMBROKE,NC,34.6920,-79.1769,204.93.39.17
+US,SCOTTCITY,MO,37.1648,-89.4816,204.93.47.216
+US,LUCEDALE,MS,30.8443,-88.5703,96.17.153.162
+PL,MIROSLAW,"",52.53,19.82,2.22.52.101
+US,CHURCHVILLE,MD,39.5659,-76.2431,23.192.161.30
+IT,BARLASSINA,"",45.65,9.13,2.18.240.114
+US,COLBY,KS,39.3420,-101.0639,23.215.15.9
+TW,ILAN,"",24.77,121.75,60.199.191.59
+CZ,OSTRAVAZABREH,"",49.80,18.22,23.62.237.137
+EC,IBARRA,"",-0.30,-78.55,165.254.205.7
+US,LAKESAINTLOUIS,MO,38.7948,-90.7836,184.85.215.170
+DE,MEININGEN,TH,50.55,10.42,80.157.170.221
+RO,JIBOU,"",47.27,23.25,80.239.237.231
+VN,BINHAN,"",10.90,106.80,96.17.180.155
+US,WHITESULPHURSPRINGS,WV,37.8461,-80.2545,184.27.45.150
+NL,PIJNACKER,"",52.02,4.43,92.122.189.85
+US,MOBERLY,MO,39.4377,-92.3968,23.215.15.9
+US,SIBLEY,IA,43.4213,-95.7453,165.254.114.164
+US,WICKENBURG,AZ,33.9689,-112.7286,184.50.26.204
+CA,DAUPHIN,MB,51.15,-100.05,23.74.8.8
+PH,ZAMBOANGA,"",18.20,120.58,58.71.107.119
+US,BRONSTON,KY,36.8981,-84.635,80.239.237.230
+AU,EIGHTMILEPLAINS,QLD,-27.58,153.10,23.209.183.61
+US,NESCOPECK,PA,41.0389,-76.1727,165.254.48.150
+US,PEARLRIVER,LA,30.4339,-89.7967,96.17.153.157
+JP,SHINMACHI,06,38.40,140.38,72.246.184.92
+US,BENTLEYVILLE,PA,40.1179,-80.0044,184.28.17.76
+US,ASHLANDCITY,TN,36.2777,-87.0046,23.220.100.223
+IN,NAGPUR,MH,21.15,79.10,124.124.40.93
+IT,BERGAMO,"",45.68,9.72,195.22.200.221
+IN,JAMNAGAR,GJ,22.47,70.07,95.101.2.122
+US,SEDONA,AZ,34.6859,-111.2845,23.5.164.143
+NL,HOOFDDORP,"",52.30,4.70,92.122.189.85
+US,IOWAPARK,TX,33.9610,-98.717,107.14.36.200
+US,KIOWA,OK,34.7289,-95.9883,66.171.227.82
+PL,STAROGARDGDANSKI,"",53.97,18.55,2.22.52.101
+RU,KRASNOGORSK,"",55.83,37.33,80.239.222.169
+CH,BULLE,"",46.62,7.07,88.221.15.111
+IN,ALLAHABAD,UP,25.45,81.85,23.57.69.159
+LT,TAURAGE,"",55.25,22.28,92.122.189.85
+FR,HAMBACH,"",49.07,7.03,2.16.117.200
+FR,VEYREMONTON,"",45.68,3.17,2.16.117.200
+US,OTSEGO,MI,42.4993,-85.713,23.63.227.214
+FR,CERGY,"",49.03,2.07,2.16.117.200
+US,HOFFMANESTATES,IL,42.0425,-88.0794,23.67.242.156
+ES,SANTIAGODECOMPOSTELA,"",42.88,-8.55,2.20.44.111
+US,CLACKAMAS,OR,45.4104,-122.5055,23.212.59.63
+ES,MURCIA,"",37.98,-1.12,2.20.44.111
+KR,JEJU,"",33.51,126.52,61.111.58.229
+CN,LAIWU,SD,36.32,117.58,117.104.138.235
+DE,GUTERSLOH,NW,51.90,8.38,2.20.142.166
+CA,WHITECOURT,AB,54.13,-115.68,184.27.179.187
+RU,NOVATOR,"",60.74,46.21,213.155.156.212
+US,WOLCOTT,CT,41.6004,-72.9736,184.25.109.213
+US,SPRINGLAKE,MI,43.1035,-86.2217,23.63.227.227
+PL,WYSZKOW,"",52.60,21.47,80.157.149.129
+BT,MONGAR,"",27.25,91.20,23.76.205.111
+CN,LONGYAN,FJ,25.18,117.03,184.50.87.176
+CA,CHATEAUGUAY,QC,45.38,-73.75,67.69.197.92
+US,PRAIRIEVILLE,LA,30.3065,-90.9499,23.212.53.64
+TR,ERENKOY,"",40.97,29.07,77.67.29.109
+PL,KOSCIERZYNA,"",54.12,17.98,2.22.52.109
+IT,FERRERO,"",45.45,7.88,2.18.240.114
+US,MOSSLANDING,CA,36.7948,-121.7864,63.217.232.22
+US,CHESTERSPRINGS,PA,40.1084,-75.6462,184.26.44.38
+RU,NIZHNINOVGOROD,"",56.33,44.00,80.239.237.80
+CA,WINKLER,MB,49.18,-97.93,23.74.8.8
+PL,LOMZA,"",53.18,22.08,2.22.52.102
+US,HOLTSSUMMIT,MO,38.6152,-92.0964,209.170.117.178
+GB,MAYFAIR,EN,51.50,-0.15,195.245.125.107
+US,WESTHOLLYWOOD,CA,34.0942,-118.3815,165.254.144.25
+AU,FREMANTLE,WA,-32.05,115.77,23.62.224.28
+US,PRAIRIEDUCHIEN,WI,43.0613,-91.0624,23.67.60.217
+ES,LUGO,"",43.00,-7.57,80.149.168.109
+FR,LACOURNEUVE,"",48.92,2.38,2.16.117.190
+US,MOUNTMORRIS,MI,43.1205,-83.6765,23.67.60.223
+BR,MONTEAPRAZIVEL,SP,-20.75,-49.70,80.239.237.231
+FR,LANGUIDIC,"",47.83,-3.17,2.16.117.190
+DE,VELTEN,BB,52.68,13.18,213.248.108.244
+US,TIPTON,IN,40.2754,-86.0469,23.74.8.24
+TR,AFYON,"",38.75,30.55,80.239.237.231
+US,LUTCHER,LA,30.0539,-90.7041,96.17.153.157
+US,SEALBEACH,CA,33.7538,-118.0713,184.50.26.194
+CA,RIMOUSKI,QC,48.43,-68.52,184.27.120.65
+US,SYLVESTER,GA,31.5445,-83.898,63.141.200.241
+UA,MEGA,"",48.13,25.43,80.239.237.230
+US,BEMIDJI,MN,47.5271,-94.7611,63.151.29.15
+FR,LAROCHELLE,"",46.17,-1.15,2.16.117.200
+US,KAPLAN,LA,29.6422,-92.4232,23.79.240.36
+ES,SEVILLE,"",37.38,-5.99,80.239.237.231
+AT,WIESELBURG,"",48.13,15.13,195.145.147.107
+PL,WIELUN,"",52.98,20.03,2.22.52.102
+RU,KOGALYM,"",62.18,74.55,2.22.52.102
+PL,MALBORK,"",54.03,19.05,80.239.222.190
+RO,FILIASI,"",44.55,23.52,2.22.52.102
+BY,KIROVA,"",51.38,30.58,2.22.52.105
+IE,MULLINGAR,"",53.53,-7.35,88.221.222.33
+JP,MISAWA,02,40.68,141.40,72.246.184.81
+US,MARINETTE,WI,45.0728,-87.8197,107.14.38.224
+US,SILVERCITY,NM,33.0124,-108.2868,184.84.180.96
+FR,CHOLET,"",47.07,-0.88,2.16.117.200
+US,CROZET,VA,38.1379,-78.7036,184.27.45.157
+US,COLMAN,SD,43.9352,-96.8289,23.74.8.8
+US,NUTLEY,NJ,40.8192,-74.1574,23.67.242.156
+US,DANIA,FL,26.0519,-80.1424,184.28.184.16
+JP,KOWA,23,34.77,136.90,23.3.104.16
+BG,RAKOVSKI,"",42.30,24.97,2.20.142.166
+CA,WEYBURN,SK,49.67,-103.85,23.215.15.22
+PL,DZIERZONIOW,"",50.72,16.65,92.122.189.85
+ES,TOMELLOSO,"",39.17,-3.02,92.122.188.163
+US,PRINCESSANNE,MD,38.1954,-75.7083,209.48.37.183
+FR,SAINTPHILBERTDEGRANDLIEU,"",47.03,-1.63,81.52.201.82
+FR,MONTBELIARD,"",47.52,6.80,2.16.117.200
+DE,STRUTHHELMERSHOF,TH,50.75,10.50,77.67.27.235
+US,SOUTHOLD,NY,41.0609,-72.426,184.26.44.38
+PL,ZAWIERCIE,"",50.50,19.43,213.200.109.173
+CA,GATINEAU,QC,45.48,-75.65,67.69.197.92
+US,KERHONKSON,NY,41.7943,-74.3146,24.143.199.156
+US,PELLCITY,AL,33.5807,-86.3463,184.51.35.226
+CZ,NEUSTUPOV,"",49.62,14.70,2.20.142.166
+ES,FRANCO,"",42.72,-2.70,2.20.44.111
+RS,KOM,"",43.43,19.40,2.20.45.104
+IR,KORDESTAN,"",30.68,50.16,92.122.189.114
+US,HIGHRIDGE,MO,38.4787,-90.5323,96.17.14.16
+GB,FINCHLEY,EN,51.60,-0.17,23.67.255.158
+US,DIAMONDHEAD,MS,30.3820,-89.3694,92.122.188.163
+US,POQUOSON,VA,37.1315,-76.3584,204.2.243.143
+US,CHEVYCHASE,MD,38.9825,-77.0796,184.27.45.157
+UG,MAKERERE,"",0.33,32.57,195.245.125.114
+CZ,CHEB,"",50.07,12.37,23.74.24.69
+US,FALLSCITY,NE,40.1276,-95.5661,23.63.227.227
+IN,TIRUPPUR,TN,11.10,77.35,65.116.149.89
+US,CLARENDONHILLS,IL,41.7892,-87.957,23.67.60.222
+VN,LAI,"",15.77,107.72,23.5.165.167
+RS,DESPOTOVAC,"",44.09,21.45,23.62.237.138
+US,BEEVILLE,TX,28.4569,-97.768,184.26.93.111
+AU,ROCKDALE,NSW,-33.95,151.13,104.72.70.95
+AT,KLEDERING,"",48.13,16.43,23.74.24.66
+US,KIMBERLY,AL,33.7678,-86.8087,204.2.243.143
+US,EXPORT,PA,40.4280,-79.6049,184.26.44.42
+RU,LESNAYA,"",55.23,39.80,2.21.240.40
+JP,MAEBASHI,10,36.38,139.07,72.246.191.16
+SK,SENEC,"",48.22,17.40,23.14.94.228
+DE,KOCH,NW,51.17,6.33,23.212.108.28
+DE,BEIERSDORF,BY,50.28,10.93,2.20.142.166
+DE,RATINGEN,NW,51.30,6.85,2.16.217.206
+IN,SHIV,RJ,26.18,71.25,96.17.182.136
+FR,NEVERS,"",46.98,3.17,2.16.117.200
+US,FORTMITCHELL,KY,39.0279,-84.5635,184.51.147.6
+AT,FRITZ,"",47.53,15.87,23.62.237.137
+US,TALLASSEE,AL,32.5595,-85.8976,23.33.186.101
+HU,VARPALOTA,"",47.20,18.13,23.14.94.228
+TR,GAZIANTEP,"",37.08,37.37,23.74.24.69
+US,CHARLEROI,PA,40.1402,-79.9469,23.192.161.30
+AE,ALAIN,"",24.22,55.77,2.20.249.12
+US,FOSTORIA,OH,41.1667,-83.402,205.185.195.168
+US,MEADE,KS,37.2174,-100.3456,23.215.15.9
+US,GLOUCESTERPOINT,VA,37.2577,-76.4965,23.220.148.108
+US,WERNERSVILLE,PA,40.3472,-76.0868,23.192.161.21
+US,DAVIDSON,NC,35.4822,-80.8049,184.27.45.157
+AF,KHAN,"",33.60,70.08,79.140.94.183
+JP,SANYO,35,34.03,131.10,117.104.139.160
+MX,OAXACA,OAX,16.41,-96.63,107.14.43.30
+US,SAINTROBERT,MO,37.8445,-92.1463,209.170.117.178
+TR,SAKARYA,"",40.77,30.40,92.122.188.163
+FR,SAINTAIGNANGRANDLIEU,"",47.12,-1.63,2.16.117.200
+IT,FORLI,"",44.22,12.05,2.18.240.95
+US,HENNESSEY,OK,36.0641,-97.8809,174.76.226.110
+IT,SANSEVERINO,"",40.08,15.35,2.18.240.95
+AT,PERNITZ,"",47.90,15.97,195.145.147.101
+US,MARCUSHOOK,PA,39.8393,-75.4661,23.67.242.156
+JP,MIKATA,18,35.55,135.92,23.61.250.113
+KZ,TENGE,"",43.31,52.86,2.21.240.61
+RU,CHEREMKHOVO,"",60.73,30.50,2.21.240.61
+JP,KANUMA,09,36.55,139.73,23.3.104.16
+US,TOLLESON,AZ,33.1732,-112.3475,63.226.34.176
+DE,WEIHENSTEPHAN,BY,48.40,11.73,23.14.94.214
+RU,ENGELS,"",51.50,46.12,23.14.94.220
+US,CARBONCLIFF,IL,41.4962,-90.3857,165.254.134.201
+US,LANSDOWNE,PA,39.9372,-75.2636,23.67.242.156
+IN,BOLPUR,WB,23.67,87.72,23.57.76.18
+DE,BACKNANG,BW,48.95,9.43,194.25.95.225
+KZ,SEMIPALATINSK,"",50.41,80.23,23.14.94.224
+ID,PINANG,"",-6.22,106.67,23.0.162.40
+IN,SHRINAGAR,MP,22.95,79.52,96.17.182.130
+US,LARNED,KS,38.1779,-99.1746,23.215.15.22
+US,PORTWASHINGTON,WI,43.4225,-87.8809,65.113.249.8
+VN,BINHDUONG,"",15.85,108.38,165.254.1.165
+EC,BANOS,"",-1.40,-78.42,165.254.205.7
+US,WHITESTONE,NY,40.7862,-73.811,24.143.199.156
+DE,HILDEN,NW,51.17,6.93,23.14.94.224
+US,PINEBROOK,NJ,40.8673,-74.3427,184.26.44.42
+JP,OHORI,12,35.33,139.87,23.3.74.112
+PH,BINONDO,"",14.60,120.97,184.50.26.179
+MK,CAIR,"",42.02,21.44,195.145.147.101
+DE,WINTERBACH,RP,49.87,7.63,23.14.94.224
+PH,NOVALICHES,"",14.72,121.03,58.71.107.116
+US,PHILLIPS,WI,45.7439,-90.2959,23.74.8.24
+US,":{",NC,,,
+AT,LENZING,"",47.97,13.62,84.53.146.35
+US,NATIONALCITY,CA,32.6702,-117.0918,23.216.10.78
+MX,TLAQUEPAQUE,JAL,20.65,-103.32,187.141.2.154
+US,AHOSKIE,NC,36.3091,-77.0137,209.18.41.23
+US,FRONTROYAL,VA,38.9572,-78.2104,184.26.44.40
+US,NEWHAMPTON,IA,43.0559,-92.3113,63.216.54.229
+ZM,KAFUE,"",-15.77,28.18,41.193.163.45
+DE,GIESEN,NI,52.20,9.90,80.157.150.192
+AR,MARCOSPAZ,"",-34.78,-58.85,23.74.2.12
+IN,KOLLAM,KL,11.45,75.68,117.239.240.96
+DE,BERKENTHIN,SH,53.73,10.65,92.122.207.179
+GB,HEMELHEMPSTEAD,EN,51.75,-0.47,23.212.108.8
+AU,FITZROY,VIC,-37.78,144.98,104.72.70.96
+FR,SATURARGUES,"",43.72,4.12,2.16.117.200
+GR,ARGOS,"",37.63,22.73,79.140.94.254
+PL,CHOJNOW,"",52.02,21.08,77.67.96.114
+TW,MIAOLI,"",24.57,120.82,61.220.62.175
+US,HOBBS,NM,32.6132,-103.3269,63.216.54.231
+IN,NAINITAL,UL,29.38,79.45,117.239.91.82
+RU,OREKHOVOZUEVO,"",55.82,38.98,213.155.156.206
+CZ,OBRANY,"",49.23,16.65,23.62.237.135
+PL,PONIATOWA,"",51.18,22.13,80.15.235.161
+DE,GOLDBACH,BY,49.99,9.19,23.14.94.214
+FR,SAINTLO,"",49.12,-1.08,2.16.117.200
+SE,SODERMALM,AB,59.32,18.08,213.155.156.206
+HU,SARVAR,"",47.25,16.93,23.62.237.138
+RU,NOVOROSSISK,"",44.72,37.77,2.21.240.61
+US,GAUTIER,MS,30.4104,-88.6488,24.143.197.189
+US,IMPERIALBEACH,CA,32.5734,-117.1175,23.220.149.124
+IT,PIAZZA,"",45.58,10.13,193.45.15.199
+US,CHEHALIS,WA,46.6561,-122.9934,67.131.104.6
+US,MARLIN,TX,31.3313,-96.8629,63.216.54.216
+US,WESTHARRISON,NY,41.0555,-73.7433,184.26.44.40
+US,BARBOURSVILLE,WV,38.3904,-82.2418,209.48.37.188
+US,NOWATA,OK,36.6745,-95.6917,63.235.21.141
+US,ELMIRAGE,AZ,33.5859,-112.3345,184.50.26.194
+IL,KINERET,"",32.71,35.57,212.143.162.162
+RO,BARLAD,"",46.23,27.67,81.196.26.198
+CZ,KLATOVY,"",49.40,13.30,23.62.237.133
+PL,ZIELONAGORA,"",51.70,19.70,2.22.52.101
+IN,PATAMATA,AP,16.48,80.65,23.205.118.106
+IT,MOZZATE,"",45.68,8.95,193.45.15.198
+FR,PANTIN,"",48.90,2.40,2.16.117.200
+RO,GIURGIU,"",43.88,25.97,88.221.93.150
+US,CRYSTALSPRINGS,MS,32.0027,-90.4734,65.113.249.8
+IN,MEERUT,UP,28.98,77.70,117.239.189.99
+CA,COBOURG,ON,43.97,-78.17,72.246.43.237
+DE,DIRLEWANG,BY,48.00,10.50,80.157.170.231
+US,STONYPOINT,NY,41.2394,-74.039,23.67.242.156
+DE,LIPPSTADT,NW,51.67,8.35,195.95.193.132
+HR,VARAZDIN,"",46.31,16.34,23.14.94.220
+FR,SURESNES,"",48.87,2.23,88.221.15.110
+KR,NAMSANDONG,"",37.72,126.50,23.14.94.214
+MY,SEPANG,"",2.70,101.75,58.26.185.125
+MX,MADERO,MIC,19.40,-101.27,187.210.208.101
+CN,LINCHENG,ZJ,30.93,119.79,117.103.188.205
+CZ,RUDOLTICE,"",49.70,14.60,2.16.217.211
+RO,MOLDOVANOUA,"",44.77,21.67,80.239.222.169
+AT,WILFERSDORF,"",48.27,16.10,46.33.70.97
+US,BUCHANAN,GA,33.8511,-85.2067,212.25.69.145
+PL,BRZESKO,"",49.97,20.62,80.239.222.167
+NO,KONGSVINGER,"",60.20,12.00,2.21.240.40
+RO,REGHIN,"",46.77,24.70,81.196.26.198
+US,MONONA,IA,43.0888,-91.4288,65.113.249.11
+JP,WASEDA,15,38.30,139.55,23.3.104.29
+PL,ZABKI,"",52.28,21.12,2.22.52.105
+RO,BISTRITA,"",45.18,24.05,81.196.26.237
+IN,KOLHAPUR,MH,16.70,74.22,117.239.189.111
+CA,MONTREALNORD,QC,45.60,-73.62,67.69.197.106
+CO,RIOHACHA,"",11.55,-72.92,190.90.221.149
+AU,MOONAH,TAS,-42.85,147.30,150.101.152.249
+US,WILLIAMSTON,NC,35.7282,-77.0495,23.5.164.143
+US,UNITY,ME,44.5885,-69.3433,23.212.53.64
+FR,SCHILTIGHEIM,"",48.60,7.75,2.16.117.190
+US,WAHPETON,ND,46.2654,-96.6056,63.216.54.236
+HU,VESZPREM,"",47.10,17.92,23.14.94.224
+FR,BELLEGARDESURVALSERINE,"",46.10,5.82,88.221.83.140
+CA,BROCKVILLE,ON,44.58,-75.68,23.79.255.153
+CA,VALCOURT,QC,45.48,-72.32,67.69.197.160
+US,WESTVILLE,IL,40.0417,-87.6306,204.93.47.220
+US,JESSUP,MD,39.1490,-76.7842,184.27.179.159
+NL,VORDEN,"",52.10,6.32,92.122.189.85
+IN,BHIMASHANKAR,MH,19.07,73.53,65.113.249.8
+IT,MAGNAGO,"",45.58,8.80,2.18.240.114
+ZA,RIVONIA,"",-26.05,28.05,41.193.163.53
+MK,SVETINIKOLE,"",41.87,21.94,23.74.24.69
+BE,NAMUR,"",50.47,4.87,23.62.100.152
+FR,GARGESLESGONESSE,"",48.97,2.42,2.16.117.200
+US,NEWBERRY,MI,46.4960,-85.4887,23.79.240.48
+AU,WAGGAWAGGA,NSW,-35.12,147.37,203.26.28.250
+AT,SOMMEREIN,"",47.98,16.65,195.145.147.108
+RU,SKALA,"",55.38,82.77,2.21.240.40
+US,LEESPORT,PA,40.4116,-75.999,184.26.44.38
+AT,STEYREGG,"",48.28,14.37,195.145.147.101
+IR,KISH,"",32.86,49.70,23.215.60.48
+JP,MOKA,09,36.43,140.02,72.246.191.16
+US,HIRAM,GA,33.8668,-84.7649,72.246.247.30
+MK,RADOVIS,"",41.64,22.46,95.101.34.109
+US,BREWER,ME,44.7782,-68.725,107.14.38.224
+SV,ANTIGUOCUSCATLAN,"",13.68,-89.23,23.33.186.101
+IN,GUWAHATI,AS,26.18,91.73,23.57.76.20
+US,DYERSVILLE,IA,42.4950,-91.1159,63.216.54.229
+FR,AULNAYSOUSBOIS,"",48.95,2.52,2.16.117.190
+US,COLLEGEPLACE,WA,46.0427,-118.4036,184.27.179.159
+JP,KINJO,12,35.92,139.88,72.246.191.16
+DE,NEUWIESE,SN,51.47,14.22,195.95.193.147
+TR,ANTEP,"",37.08,37.37,193.45.15.198
+IN,BODHGAYA,BR,24.70,84.98,23.205.118.109
+US,CAMPLEJEUNE,NC,34.7003,-77.3614,23.79.240.36
+US,MACEDONIA,OH,41.3152,-81.498,63.216.54.216
+SE,GALLIVARE,BD,67.13,20.70,80.239.237.80
+US,DELEON,TX,32.1142,-98.6051,23.212.53.64
+US,KINGSFORD,MI,45.8086,-88.101,72.246.247.30
+AT,NEUNKIRCHEN,"",47.72,16.08,23.74.24.69
+JP,YASHIMA,05,39.22,140.13,23.3.104.29
+IN,MACHILIPATNAM,AP,16.17,81.13,124.124.40.93
+PL,OSWIECIM,"",50.03,19.23,80.239.149.123
+AT,OEDT,"",48.75,15.48,84.53.146.37
+HU,MISEFA,"",46.80,16.98,195.145.147.109
+FR,HENINBEAUMONT,"",50.42,2.93,2.16.117.190
+TH,HATYAI,"",7.02,100.47,110.164.11.181
+PL,WIELOGLOWY,"",49.67,20.70,80.15.235.156
+PR,SANGERMAN,"",18.0846,-67.0463,204.2.243.135
+CN,FANYU,GD,23.12,113.25,184.84.239.175
+PL,MOSTOW,"",52.10,22.75,2.22.52.101
+AT,GASTHOF,"",47.43,13.38,46.33.70.104
+AR,MORENO,"",-34.46,-58.93,80.239.237.231
+PL,OSTROW,"",52.10,21.38,80.157.149.181
+AT,AXAMS,"",47.23,11.30,195.145.147.107
+US,SANDYHOOK,VA,37.7897,-77.9807,184.26.44.38
+AT,ERB,"",48.10,13.18,195.145.147.109
+US,CUTLER,CA,36.4976,-119.2842,63.217.8.169
+IR,ZAHEDAN,"",28.75,53.80,2.20.142.166
+PL,KWIDZYN,"",53.73,18.92,2.22.52.102
+US,THONOTOSASSA,FL,28.1050,-82.287,23.33.186.101
+PL,NIEPOLOMICE,"",50.03,20.23,80.15.235.156
+US,KENEDY,TX,28.7695,-97.8354,96.17.163.165
+RU,TOMARI,"",47.77,142.07,96.7.251.95
+UA,LISICHANSK,"",48.92,38.42,92.122.188.163
+CZ,MOST,"",50.53,13.65,23.74.24.69
+RO,MEDGIDIA,"",44.25,28.28,88.221.93.157
+BR,CERQUILHO,SP,-23.17,-47.74,92.122.188.163
+US,ATTICA,IN,40.2530,-87.1864,65.113.249.8
+BR,BRAGANCAPAULISTA,SP,-22.95,-46.57,200.174.107.42
+AT,KAPPL,"",47.52,10.47,195.145.147.108
+KR,JINJU,"",35.19,128.08,61.111.58.43
+IN,ULHASNAGAR,MH,19.22,73.15,213.248.108.244
+PL,NOWYSACZ,"",49.63,20.72,77.67.96.114
+BA,TRAVNIK,"",43.37,18.75,2.20.142.166
+AR,COMODORORIVADAVIA,"",-45.87,-67.50,190.98.167.230
+IN,CALICUT,KL,11.25,75.77,117.239.240.96
+US,LABELLE,FL,26.6279,-81.3332,23.79.240.36
+US,CASCADE,IA,42.2695,-91.0027,65.113.249.11
+RS,RUMA,"",45.01,19.82,23.62.237.135
+RU,BALASHIKHA,"",55.80,37.95,2.21.240.61
+PL,KOZIEGLOWY,"",51.77,21.00,2.22.52.101
+HR,VINKOVCI,"",45.29,18.80,46.33.70.104
+IN,ALIGARH,UP,27.45,83.13,184.25.157.169
+US,LENNON,MI,42.9989,-83.9455,23.74.8.8
+US,TONTOBASIN,AZ,33.8677,-111.3122,23.74.8.24
+US,POCAHONTAS,AR,36.3332,-91.0542,173.197.194.159
+RO,CAMPIATURZII,"",46.55,23.88,92.122.188.161
+HU,LAJOSMIZSE,"",47.02,19.55,23.62.237.138
+SK,ZVOLEN,"",48.58,19.13,23.62.237.133
+US,HAMLET,NC,34.8875,-79.6665,184.28.127.55
+ID,TEBET,"",-6.23,106.85,23.0.162.21
+RU,CHERNOGOLOVKA,"",56.00,38.37,92.122.188.163
+PL,ZALUSKI,"",52.17,20.93,80.239.222.190
+FR,POUILLYSOUSCHARLIEU,"",46.15,4.12,2.16.117.200
+BG,SHUMEN,"",43.27,26.92,2.20.142.166
+GR,SERRES,"",41.08,23.55,80.157.169.18
+US,ZAPATA,TX,26.8906,-99.1308,184.26.93.116
+RU,ELISTA,"",47.44,44.46,80.239.222.167
+US,HOMERVILLE,GA,31.0656,-82.7583,23.79.240.48
+BG,SILISTRA,"",44.12,27.27,23.14.94.228
+US,KATHLEEN,GA,32.4765,-83.6061,184.51.35.215
+PH,PARANAQUE,"",14.51,120.99,120.28.5.112
+CN,JINCHANG,GS,38.50,102.17,72.246.191.120
+IN,MADURAI,TN,9.93,78.12,92.122.188.163
+US,WALKERTOWN,NC,36.1899,-80.1591,209.18.41.23
+IL,HOLON,"",32.01,34.77,212.25.69.134
+US,GARFIELD,NJ,40.8788,-74.1075,23.67.242.139
+AR,GALVEZ,"",-33.03,-60.63,177.159.181.174
+DE,ED,BY,47.78,11.80,80.157.170.158
+RO,MOTRU,"",44.80,22.97,92.122.188.163
+DE,AALEN,BW,48.83,10.10,23.74.24.66
+DK,BORRIS,"",55.97,8.65,2.21.240.40
+US,MARYLANDHEIGHTS,MO,38.7275,-90.4524,204.93.47.216
+US,AMELIACOURTHOUSE,VA,37.3498,-77.9661,184.51.35.215
+DE,GRAS,BY,47.75,12.67,194.25.95.219
+US,PLAINSBORO,NJ,40.3338,-74.5836,184.26.44.42
+US,SILVERSPRINGS,NV,39.3955,-119.2669,23.61.195.165
+US,EASTHADDAM,CT,41.4660,-72.3865,184.25.109.196
+BG,SAMOKOV,"",42.33,23.55,93.186.137.231
+CZ,FRANTISEK,"",49.87,18.27,23.62.237.137
+AR,MARDELPLATA,"",-38.00,-57.55,190.98.167.230
+US,PORTDEPOSIT,MD,39.6245,-76.0756,65.121.209.127
+US,FORDYCE,AR,33.8659,-92.4841,23.74.8.8
+ID,SOLOK,"",-0.80,100.65,80.239.237.230
+FR,SASSETOTLEMAUCONDUIT,"",49.80,0.53,2.16.117.200
+US,LENOX,MA,42.3695,-73.2774,107.14.38.227
+US,BRUCE,WI,45.4985,-91.3289,23.74.8.24
+AT,PASCHING,"",48.25,14.20,23.62.237.138
+IN,DHARMAPURI,TN,12.13,78.17,23.205.118.106
+VE,LAGUAIRA,"",10.60,-66.93,23.74.2.7
+IL,EILAT,"",29.56,34.95,212.25.69.142
+IN,THANJAVUR,TN,10.80,79.15,117.239.240.96
+NZ,MOSGIEL,"",-45.88,170.35,184.28.126.7
+US,HANCOCK,MI,47.1715,-88.5503,65.113.249.11
+CH,GAMPELEN,"",47.02,7.05,193.247.167.211
+US,NORTHWOOD,OH,41.6045,-83.4717,65.113.249.11
+FR,VILLEFRANCHE,"",48.23,2.95,2.16.117.200
+CZ,PISEK,"",50.15,15.50,23.62.237.137
+BO,ORURO,"",-17.77,-67.48,72.246.65.37
+HR,SIBENIK,"",45.82,17.18,80.15.235.161
+EC,PASTAZA,"",0.04,-77.17,184.26.44.38
+RO,JILAVA,"",44.33,26.08,194.25.95.219
+DE,ROTHENBURG,BY,50.32,11.77,80.157.150.169
+US,TARRYTOWN,NY,41.0851,-73.846,23.79.255.149
+CA,TERREBONNE,QC,45.68,-73.63,67.69.197.92
+PL,ZDUNY,"",52.15,19.82,80.157.149.129
+US,LINN,MO,38.4764,-91.7793,23.63.227.227
+UA,VINNITSA,"",49.23,28.48,2.22.52.101
+CZ,VESELINADMORAVOU,"",48.95,17.40,92.122.188.163
+US,WAYZATA,MN,44.9781,-93.5263,23.67.60.223
+DE,BADHARZBURG,NI,51.88,10.57,92.122.207.179
+SE,KUNGSBACKA,N,57.48,12.07,2.21.240.40
+TH,RANGSIT,"",13.98,100.62,110.164.11.192
+NO,GRORUD,"",59.95,10.88,2.21.240.40
+US,NELSONVILLE,OH,39.4502,-82.2473,72.247.10.237
+RU,DOROZHNYY,"",59.22,39.88,2.21.240.40
+SE,KATRINEHOLM,D,59.00,16.20,213.155.156.212
+US,FITZGERALD,GA,31.7597,-83.2209,72.246.247.30
+GB,BUCKINGHAM,EN,52.00,-0.98,23.61.251.143
+DE,LEONBERG,BW,48.80,9.02,23.14.94.220
+US,FRUITLANDPARK,FL,28.8719,-81.9072,23.79.240.48
+US,NEAHBAY,WA,48.3685,-124.6238,165.254.1.165
+RU,OKHA,"",56.49,33.89,96.7.251.95
+FI,MARIEHAMN,"",60.10,19.95,2.21.240.40
+IN,KUKATPALLI,AP,17.48,78.42,117.239.240.96
+US,RIOLINDA,CA,38.6864,-121.4408,96.17.12.44
+GB,PADDINGTON,EN,51.50,-0.18,173.222.211.203
+US,NOKOMIS,FL,27.1186,-82.4447,23.79.240.36
+CH,HERISAU,"",47.40,9.27,213.254.212.102
+US,DILLSBURG,PA,40.0904,-77.0293,23.192.161.30
+DK,PADBORG,"",54.82,9.37,2.21.240.61
+US,LEMOYNE,PA,40.2478,-76.9006,23.192.161.21
+US,WRIGHTSVILLE,GA,32.7293,-82.7399,72.246.247.30
+CN,LOUDI,HN,27.75,111.98,72.246.191.19
+US,BRIDGMAN,MI,41.9364,-86.5496,23.67.60.223
+US,BETHPAGE,NY,40.7426,-73.4861,184.26.44.38
+US,EASTPOINTE,MI,42.4657,-82.946,23.63.227.227
+SI,ZRECE,"",46.38,15.37,194.25.95.214
+US,WICKLIFFE,OH,41.5969,-81.4651,107.14.38.218
+IN,SHILLONG,ML,25.58,91.87,124.124.40.93
+US,WELLSVILLE,NY,42.0803,-77.9333,107.14.38.217
+US,HAVELOCK,NC,34.8925,-76.9041,184.27.45.150
+TH,UTHAI,"",14.37,100.67,217.212.227.25
+TR,KAHRAMANMARAS,"",37.60,36.92,193.45.15.199
+KR,KARI,"",36.80,126.90,112.175.42.125
+US,ONAWA,IA,42.0513,-96.1326,165.254.207.117
+AU,BOTANY,NSW,-33.97,151.20,104.72.70.96
+IN,GUINDY,TN,13.01,80.22,23.205.118.109
+TW,HSINCHUANG,"",25.03,121.45,61.220.62.175
+US,KENTWOOD,LA,30.8810,-90.466,184.85.215.170
+US,PITMAN,NJ,39.7363,-75.1333,184.26.44.38
+AT,KAPFENBERG,"",47.43,15.30,2.16.217.211
+US,ALAMO,TX,26.2003,-98.1112,107.14.43.29
+US,ALTAVISTA,VA,37.1291,-79.2868,23.220.148.122
+US,STORMLAKE,IA,42.6740,-95.1635,23.63.227.214
+BE,KNOKKE,"",50.85,3.38,23.62.100.154
+JP,HYOGO,01,43.37,144.43,72.246.191.16
+KZ,SHKOLA,"",46.55,48.82,2.21.240.40
+US,GLADEWATER,TX,32.5672,-94.9346,23.5.164.143
+BG,DIMITROVGRAD,"",42.05,25.60,93.186.137.230
+TR,GAZI,"",38.25,35.47,23.14.94.214
+UA,DMITROVICH,"",49.77,23.35,92.122.215.89
+US,CUMBERLANDCENTER,ME,43.7981,-70.2656,107.14.38.218
+AT,ANIF,"",47.75,13.07,195.145.147.107
+US,WEAVERVILLE,NC,35.7234,-82.5239,184.27.45.150
+FR,MEY,"",49.13,6.23,23.200.87.58
+US,GEORGEWEST,TX,28.2189,-98.1396,184.25.157.162
+PH,FERNANDO,"",13.95,121.38,58.71.107.120
+JP,MITSUKE,22,34.72,137.87,23.3.104.29
+US,MILLRY,AL,31.6272,-88.354,184.51.35.226
+IT,LUCA,"",46.01,12.36,96.17.180.155
+US,BUHLER,KS,38.1245,-97.7604,23.215.15.22
+US,CLARENCE,NY,42.9851,-78.614,107.14.38.224
+US,MANISTEE,MI,44.1909,-86.1855,23.63.227.227
+US,CRYSTALRIVER,FL,28.9023,-82.5928,23.33.186.101
+IN,MOGA,PB,30.80,75.17,96.17.182.136
+PH,ROXAS,"",12.58,121.52,23.76.205.111
+CA,CHARLESBOURG,QC,46.87,-71.27,72.246.43.233
+NL,LEIDERDORP,"",52.15,4.53,92.122.189.85
+GB,ACCRINGTON,EN,53.77,-2.35,195.245.125.114
+SE,SOLLENTUNA,AB,59.42,17.95,213.155.156.212
+US,VIDALIA,GA,32.1357,-82.4052,72.246.247.5
+US,RANDALLSTOWN,MD,39.3744,-76.8156,184.27.45.150
+US,OLIVET,MI,42.4347,-84.8844,192.80.13.117
+US,HUDSONFALLS,NY,43.3537,-73.5472,23.67.242.139
+US,SCOTTSBLUFF,NE,41.9186,-103.6441,184.85.215.170
+US,NATCHEZ,MS,31.5340,-91.3231,96.17.153.157
+US,MILBANK,SD,45.1526,-96.6079,23.74.8.8
+RU,IM,"",52.82,138.33,72.246.184.81
+US,CLYDE,NC,35.6610,-82.9473,96.16.12.228
+US,GALAX,VA,36.6484,-80.9203,23.79.240.37
+JP,IKAWA,22,35.22,138.25,96.7.251.95
+US,LOCKHAVEN,PA,41.2558,-77.4987,184.28.17.55
+US,SHOEMAKERSVILLE,PA,40.4930,-75.9492,23.192.161.21
+IL,MAOZ,"",32.48,35.55,212.25.69.145
+US,FAIRBURY,NE,40.1696,-97.2152,184.26.93.111
+JO,FARAH,"",32.37,35.65,95.101.34.105
+US,LYNCHSTATION,VA,37.1483,-79.3585,184.29.107.38
+US,BERNALILLO,NM,35.4078,-106.8201,63.226.34.176
+GT,QUETZALTENANGO,"",14.83,-91.52,72.246.65.38
+ID,KARAWANG,"",-6.32,107.28,23.0.162.46
+US,FORESTHILL,MD,39.5864,-76.392,209.48.37.183
+CZ,KRALUPY,"",50.23,14.32,195.27.155.188
+DE,JESSEN,SN,51.18,13.28,23.14.94.214
+PR,MERCEDITA,"",18.1144,-66.8568,92.122.215.67
+CN,XUANCHENG,AH,30.95,118.76,72.246.191.19
+CA,TOFINO,BC,49.13,-125.90,24.244.17.197
+IN,MUZAFFARNAGAR,UP,29.47,77.68,23.205.118.106
+US,EMMITSBURG,MD,39.6880,-77.3321,72.247.10.237
+DE,WALDENBURG,BW,49.19,9.64,195.145.147.101
+IN,KOTTAYAM,KL,11.83,75.57,23.205.169.195
+US,WINDBER,PA,40.2054,-78.7856,23.192.161.21
+BR,JOAOPESSOA,PB,-7.12,-34.87,72.246.216.139
+AR,MAGDALENA,"",-35.07,-57.53,92.122.188.163
+IR,SHIRGAH,"",36.29,52.90,2.22.61.102
+SE,ASAKA,O,58.07,13.67,2.21.240.40
+ID,KEBALEN,"",-6.22,106.68,23.0.162.40
+US,BRAINTREE,MA,42.2036,-71.0017,72.247.10.241
+NL,URMOND,"",51.00,5.77,92.122.189.114
+AU,ALBURY,NSW,-36.08,146.92,60.254.143.211
+NL,APPINGEDAM,"",53.32,6.87,92.122.189.114
+DE,HILDESHEIM,NI,52.15,9.97,2.16.217.211
+RO,VULCAN,"",45.63,25.42,92.122.188.161
+NL,HEIDE,"",52.93,5.77,173.222.211.190
+IR,JAHROM,"",30.08,51.72,77.67.96.116
+US,HAROLD,KY,37.4843,-82.6492,23.63.227.214
+US,LOUDON,TN,35.7114,-84.3653,72.246.247.5
+US,BAYMINETTE,AL,30.8772,-87.7146,96.17.153.162
+RU,ARTEM,"",47.77,40.31,72.246.184.92
+RU,STUPINO,"",54.90,38.07,80.239.217.238
+US,SEATmidMileRTT,WA,,,
+ES,BLANCA,"",38.18,-1.37,92.122.188.161
+DE,HAVIXBECK,NW,51.98,7.42,194.25.95.212
+US,MCFARLAND,WI,43.0035,-89.2832,184.85.215.170
+BY,KOBRYN,"",52.22,24.37,88.221.15.110
+FI,KEMI,"",65.73,24.57,193.184.164.219
+US,PITTSBORO,IN,39.8818,-86.4695,23.74.8.24
+UA,RODINSKOYE,"",48.35,37.20,92.122.188.163
+IN,WARDHA,MH,20.75,78.62,23.205.118.109
+AS,PAGOPAGO,"",-14.2702,-170.7003,184.28.126.8
+US,COOLIDGE,AZ,32.9772,-111.5231,184.50.26.179
+DK,ALBERTSLUND,"",55.65,12.35,213.155.156.207
+LV,AGENSKALNS,"",56.95,24.10,2.21.240.40
+DE,BRUCHSAL,BW,49.13,8.58,23.14.94.224
+PL,SIEDLCE,"",52.17,22.30,2.22.52.105
+BE,VILVOORDE,"",50.93,4.43,23.62.100.152
+US,MILLTOWN,WI,45.5218,-92.5019,23.63.227.227
+TR,ADIYAMAN,"",37.92,34.65,23.14.94.220
+FR,BOURGOGNE,"",49.35,4.07,81.52.201.82
+JP,WARABI,11,35.83,139.71,23.3.104.29
+US,NORTHSALTLAKE,UT,40.8433,-111.9231,96.17.180.155
+ID,SALATIGA,"",-7.32,110.50,23.0.162.54
+US,LEADVILLE,CO,39.2128,-106.3404,184.85.215.170
+RO,TECUCI,"",44.35,24.85,88.221.93.157
+US,SCOTCHPLAINS,NJ,40.6176,-74.3695,23.67.242.156
+PL,SOBOTKA,"",51.15,20.70,2.22.52.109
+RO,TULCEA,"",45.17,28.80,88.221.93.157
+IR,ABAD,"",32.56,51.90,96.17.182.136
+US,ROCKWELLCITY,IA,42.3850,-94.6304,184.27.120.50
+CO,YUMBO,"",3.58,-76.49,92.122.188.161
+RU,RUMYANTSEVO,"",55.63,37.43,2.21.240.61
+MG,TOAMASINA,"",-18.17,49.38,195.10.8.196
+FR,TOURLAVILLE,"",49.63,-1.57,2.16.117.200
+US,CANDOR,NY,42.2148,-76.3401,204.94.155.231
+IT,VAPRIODAGOGNA,"",45.60,8.55,2.18.240.95
+US,DANE,WI,43.2444,-89.5211,184.85.215.170
+US,WADESBORO,NC,35.0383,-80.0776,63.216.54.236
+RO,LUPENI,"",46.38,25.22,88.221.93.157
+TH,CHAIYAPHUM,"",15.80,102.03,180.180.251.220
+PL,PLOCK,"",52.55,19.70,80.239.222.169
+AT,STEYR,"",48.05,14.42,195.145.147.109
+US,WALBRIDGE,OH,41.5666,-83.5031,107.14.38.227
+US,NORTHADAMS,MA,42.6996,-73.0936,107.14.42.48
+FR,ROANNE,"",46.03,4.07,2.16.117.190
+US,NEWLONDON,NH,43.4164,-71.9863,165.254.35.182
+US,PORTCLINTON,OH,41.5070,-82.931,23.74.8.8
+PL,ZBOJNO,"",52.75,19.75,80.239.149.123
+US,NEWMAN,CA,37.2808,-121.2434,65.113.249.11
+NL,MEPPEL,"",52.70,6.20,92.122.189.114
+US,WOMELSDORF,PA,40.3905,-76.2083,23.192.161.21
+US,JAMISON,PA,40.2534,-75.0882,23.67.242.139
+US,WAMEGO,KS,39.2480,-96.3175,174.76.226.110
+CZ,KRENICE,"",50.03,14.67,23.62.237.133
+US,BETHEL,OH,38.9479,-84.0585,204.93.47.216
+US,HOLMES,PA,39.9003,-75.3086,184.27.45.150
+FR,PLANDECUQUES,"",43.35,5.47,2.16.117.200
+US,LEWES,DE,38.7339,-75.1733,23.192.161.16
+BR,PONTAGROSSA,PR,-25.08,-50.15,187.59.4.147
+FR,PONTDUCHATEAU,"",45.80,3.25,2.16.117.190
+TH,AYUDHYA,"",14.35,100.55,202.183.253.39
+US,SADDLEBROOK,NJ,40.9035,-74.0953,184.26.44.40
+DE,GARBSEN,NI,52.42,9.60,23.65.29.106
+PH,ANGELES,"",14.00,121.08,23.76.205.90
+CA,KINGCITY,ON,43.93,-79.53,72.246.43.232
+CZ,BYSTRICENADPERNSTEJNEM,"",49.52,16.27,23.62.237.138
+NO,RYGGE,"",59.38,10.72,82.96.58.85
+VN,HOANG,"",20.83,106.67,23.76.205.90
+US,DURAND,MI,42.9073,-83.9967,23.63.227.214
+JP,IRUMA,22,34.62,138.80,23.3.104.16
+RU,IRON,"",43.31,44.08,2.22.52.101
+DE,WOLFRATSHAUSEN,BY,47.92,11.42,195.145.147.101
+CA,NORTHBAY,ON,46.30,-79.45,92.122.189.85
+US,MCCOOK,NE,40.1761,-100.6468,23.215.15.32
+US,NEWEFFINGTON,SD,45.8778,-96.9166,23.79.255.153
+DE,BERGER,NW,51.72,7.50,194.25.95.212
+FR,SAINTSYMPHORIENDOZON,"",45.63,4.87,2.16.117.190
+FR,NOGENTSUROISE,"",49.27,2.47,2.16.117.190
+US,MIDDLEBURG,FL,30.0689,-81.8609,184.51.145.22
+SE,BORAS,O,57.72,12.92,23.65.29.106
+CN,CHENZHOU,HN,25.80,113.03,72.246.191.16
+CN,HUANGZHONG,QH,36.52,101.67,72.246.191.19
+US,UNIVERSITYCENTER,MI,43.5595,-83.9905,23.79.255.153
+US,BLOOMINGDALE,IL,41.9509,-88.0873,96.17.14.15
+JP,TSUYAMA,33,35.05,134.00,184.51.199.132
+KZ,PUSHKIN,"",50.29,73.79,80.239.237.80
+FI,TEUVA,"",62.48,21.73,193.184.164.239
+US,CAMBY,IN,39.6290,-86.3038,65.113.249.11
+US,MARNE,MI,43.0292,-85.8434,184.25.157.169
+BY,LOGOYSK,"",54.21,27.85,80.239.149.123
+US,VIRGINIA,MN,47.5233,-92.5364,23.77.234.35
+US,MOUNTRAINIER,MD,38.9430,-76.9649,23.192.161.16
+JP,UCHISAIWAICHO,13,35.67,139.75,72.246.184.89
+IN,BIHARSHARIF,BR,25.18,85.52,96.17.182.136
+DE,ILMENAU,TH,50.68,10.90,23.14.94.214
+AR,COLON,"",-33.89,-61.11,190.98.167.230
+AT,GROSSDORF,"",47.52,15.08,195.145.147.108
+RU,AVANGARD,"",54.47,37.12,80.239.237.93
+US,LEAVITTSBURG,OH,41.2542,-80.9112,107.14.38.227
+CN,CHENGMAI,HI,19.73,109.98,72.246.191.19
+PL,TARNOW,"",51.80,21.45,80.239.222.167
+US,GERING,NE,41.7826,-103.6811,184.85.215.165
+US,OSAGEBEACH,MO,38.1262,-92.6898,204.93.47.216
+US,VALLIANT,OK,33.9874,-95.0613,63.233.112.199
+US,CARMI,IL,38.0491,-88.1124,23.63.227.214
+DE,BADVILBEL,HE,50.18,8.75,194.25.95.214
+DE,UETZE,NI,52.47,10.20,23.14.94.220
+KR,SONGNAEDONG,"",37.53,127.12,125.56.214.149
+FR,BERGUES,"",50.03,3.72,2.16.117.190
+IN,VIRAMGAM,GJ,23.12,72.03,23.205.118.109
+US,CLARENDON,TX,35.0052,-100.8663,23.216.10.78
+CN,ZHENJIANG,JS,32.21,119.43,72.246.191.19
+PL,MIELEC,"",50.28,21.42,80.239.149.123
+RO,SIGHISOARA,"",46.22,24.80,92.122.188.161
+CH,FRIBOURG,"",46.80,7.15,213.254.212.98
+US,RAWLINS,WY,41.7532,-107.3722,23.61.195.163
+US,BELLEFOURCHE,SD,44.9293,-103.7531,23.63.227.227
+US,WINTERS,CA,38.5603,-121.9994,165.254.96.242
+AU,NORTHCOTE,VIC,-37.77,145.00,150.101.152.249
+RU,SMIRNYKH,"",49.75,142.83,72.246.184.84
+US,RONCEVERTE,WV,37.7253,-80.4371,184.27.45.157
+CZ,HUSTOPECE,"",48.93,16.73,23.74.24.66
+ID,KEMANG,"",-6.27,106.80,23.0.162.46
+US,CLEELUM,WA,47.3367,-121.0238,67.131.104.6
+US,PAWPAW,MI,42.2414,-85.9105,23.74.8.24
+BO,TARIJA,"",-19.49,-65.33,23.74.2.12
+CZ,JABLUNKOV,"",49.58,18.77,23.62.237.138
+US,ELBURN,IL,41.8654,-88.4653,23.67.60.222
+DE,ZWICKAU,SN,50.73,12.50,23.14.94.220
+RU,NOVOMOSKOVSK,"",54.09,38.22,92.122.188.163
+NL,VEENENDAAL,"",52.03,5.55,92.122.189.85
+DE,CUNEWALDE,SN,51.10,14.52,195.95.193.132
+FR,PONTCHATEAU,"",47.43,-2.08,2.16.117.190
+US,TUOLUMNE,CA,37.9468,-120.25,23.61.195.163
+DE,FAHNEN,NW,51.60,8.02,80.157.150.197
+VN,BA,"",21.30,106.50,23.76.205.111
+DE,ROTTENBURG,BW,48.47,8.93,23.14.94.224
+DK,ALLER,"",55.35,9.53,23.65.29.93
+US,ORADELL,NJ,40.9548,-74.0328,23.67.242.139
+CC,BANTAMVILLAGE,"",-12.12,96.88,96.17.180.166
+SE,SKANE,S,59.48,13.33,72.246.43.233
+JP,KITA,13,26.72,142.12,23.3.104.15
+US,OLDHICKORY,TN,36.2447,-86.616,23.79.240.36
+US,FOREST,MS,32.2901,-89.4443,165.254.138.175
+US,WILLIS,TX,30.4477,-95.5183,204.2.223.91
+US,VALLEYSTREAM,NY,40.6745,-73.7041,184.26.44.38
+RO,SFANTUGHEORGHE,"",44.65,26.83,2.22.52.101
+CZ,UHERSKYBROD,"",49.03,17.65,23.62.237.133
+US,EASTALTON,IL,38.8713,-90.0443,96.17.14.15
+CH,MASSAGNO,"",46.02,8.95,194.25.95.212
+CZ,OLBRAMKOSTEL,"",48.92,15.95,23.62.237.133
+DE,BROICH,NW,50.85,7.23,77.67.27.235
+RU,DOMODEDOVO,"",55.46,37.70,80.239.217.238
+FR,TOURCOING,"",50.72,3.15,2.16.117.185
+US,DIAMONDVILLE,WY,41.7777,-110.5371,23.212.53.75
+ES,ALORA,"",36.80,-4.70,2.20.44.111
+CH,URTENEN,"",47.03,7.48,193.247.167.211
+DZ,ANNABA,"",36.90,7.77,79.140.94.234
+TW,PANCHIAO,"",25.02,121.45,92.122.188.161
+PR,LARES,"",18.2912,-66.8528,72.246.65.26
+US,CENTRAL,SC,34.7453,-82.8049,23.79.240.36
+US,NEGAUNEE,MI,46.4658,-87.5578,184.85.215.170
+US,COCHRANE,WI,44.2495,-91.8243,23.63.227.227
+IT,VEROLI,"",41.68,13.42,193.45.15.198
+VN,CHITHANH,"",13.30,109.22,23.76.205.90
+IN,BELLARY,KA,15.15,76.93,23.205.118.106
+US,SUMMIT,MS,31.2993,-90.4958,72.246.247.30
+FI,LAHTI,"",60.97,25.67,82.96.58.102
+JP,TAGAWA,06,38.68,139.75,210.175.5.183
+CH,LOSTORF,"",47.38,7.95,193.247.167.214
+RU,LUCHEGORSK,"",46.48,134.20,72.246.184.84
+SE,SANDVIK,AB,59.35,17.98,23.62.100.152
+US,HARRISONCITY,PA,40.3834,-79.6667,23.192.161.21
+GB,CHORLEY,EN,53.65,-2.62,92.122.54.12
+FR,ALES,"",44.85,0.87,2.16.117.190
+UA,BROVARY,"",50.50,30.77,217.212.227.25
+MK,VELES,"",41.72,21.78,23.62.237.133
+DE,ASCHAFFENBURG,BY,49.97,9.15,23.14.94.224
+DE,TAUCHA,ST,51.20,12.08,80.157.150.197
+AR,QUILMES,"",-34.72,-58.27,92.122.188.161
+DE,DETTINGENANDERERMS,BW,48.53,9.35,84.53.146.39
+PL,ODRA,"",49.98,18.33,2.22.52.102
+US,NETCONG,NJ,40.8970,-74.7002,23.76.205.111
+DE,WECHLOY,NI,53.15,8.13,194.25.95.225
+CH,STEFFISBURG,"",46.78,7.63,193.247.167.214
+FR,SAINTJUSTENCHAUSSEE,"",49.50,2.43,2.16.117.190
+TZ,MOSHI,"",-3.35,37.33,23.212.108.8
+NL,VENLO,"",51.37,6.17,2.16.153.173
+US,SHALIMAR,FL,30.4411,-86.568,23.215.15.22
+US,BOSCOBEL,WI,43.1080,-90.6617,165.254.207.111
+US,REDSPRINGS,NC,34.7995,-79.1524,184.51.35.226
+BJ,SA,"",11.17,3.07,23.62.100.152
+US,BELFORD,NJ,40.4200,-74.0847,23.67.242.139
+DE,POHL,RP,50.25,7.87,23.74.24.66
+DE,ITZEHOE,SH,53.92,9.52,80.157.170.154
+US,PALA,CA,33.3876,-117.0743,65.113.249.8
+FR,CARPIQUET,"",49.18,-0.45,2.16.117.197
+UA,ZAPOROZHYE,"",47.60,33.40,92.122.188.161
+DE,MOELLN,SH,53.63,10.68,92.122.207.164
+US,PARKFOREST,IL,41.4594,-87.6908,23.67.60.223
+TZ,ZANZIBAR,"",-6.17,39.18,194.221.66.90
+IT,PARMA,"",44.80,10.33,2.18.240.114
+US,ROANOKERAPIDS,NC,36.4196,-77.714,23.79.240.48
+KR,GWANGJU,"",35.15,126.92,125.56.214.166
+NO,ROROS,"",62.58,11.40,213.155.156.212
+SE,LANDSKRONA,M,55.87,12.83,213.155.156.212
+FR,FAULQUEMONT,"",49.05,6.60,23.74.24.66
+SE,MOTALA,E,58.55,15.05,2.21.240.40
+US,SAINTLEO,FL,28.3162,-82.2455,72.164.253.83
+GB,PONTYPRIDD,WA,51.60,-3.33,23.61.251.145
+NL,BENTHUIZEN,"",52.08,4.55,23.62.100.152
+DE,FARMSEN,NI,52.17,10.10,80.157.150.201
+RU,KYZYL,"",53.78,55.25,2.21.240.61
+AT,UNTERHATZENDORF,"",46.97,16.02,195.145.147.107
+US,BROOKLET,GA,32.2794,-81.623,184.51.35.226
+MY,TASEK,"",4.65,101.12,203.106.85.4
+DE,WILSDRUFF,SN,51.05,13.53,195.95.193.132
+FR,PRA,"",45.83,5.85,23.200.87.58
+US,MAUSTON,WI,43.7786,-90.0517,23.74.8.8
+US,CLEARLAKE,IA,43.1769,-93.3674,65.113.249.11
+CA,PORTAGELAPRAIRIE,MB,49.97,-98.30,23.74.8.24
+FR,MENTON,"",43.78,7.50,2.16.117.197
+FR,DEUILLABARRE,"",48.98,2.33,2.16.117.197
+US,HAWKINSVILLE,GA,32.2568,-83.5362,184.51.35.226
+IE,MALLOW,"",52.13,-8.63,88.221.222.33
+US,NEWMARTINSVILLE,WV,39.6454,-80.8449,184.27.45.157
+FR,BONNEVILLE,"",48.55,2.28,2.16.117.185
+ID,TEGAL,"",-6.87,109.13,23.0.162.54
+US,HALLSVILLE,TX,32.4986,-94.513,23.215.15.9
+IN,JAUNPUR,UP,25.73,82.68,96.17.182.127
+US,TUBAC,AZ,31.6092,-111.0466,65.113.249.8
+US,CASEY,IL,39.3139,-87.9965,23.74.8.8
+HU,DUNAPATAJ,"",46.63,19.00,23.62.237.138
+DE,NEUSTADTBEICOBURG,BY,50.32,11.12,84.53.146.39
+CN,YUEYANG,HN,29.38,113.10,72.246.191.16
+CZ,MALES,"",50.30,13.18,23.74.24.66
+US,FORTRICHARDSON,AK,61.2265,-149.6208,23.212.59.63
+RU,PEROVO,"",55.73,37.77,217.212.227.31
+IN,RANCHI,JH,23.35,85.33,92.122.188.161
+US,RAYVILLE,LA,32.4475,-91.7992,72.246.247.5
+DE,ESSLINGEN,BW,48.75,9.30,84.53.146.39
+US,EASTQUOGUE,NY,40.8496,-72.6007,184.26.44.42
+IT,MODENA,"",44.67,10.92,195.22.200.221
+PL,JAKTOROW,"",52.08,20.57,80.157.149.181
+US,MOFFAT,CO,37.9777,-105.7795,64.145.95.126
+BA,ZAVIDOVICI,"",44.45,18.15,23.62.237.133
+US,SERGEANTBLUFF,IA,42.3991,-96.3551,165.254.207.117
+BR,BARRETOS,SP,-20.55,-48.55,177.159.174.13
+ID,CIKARANG,"",-6.25,107.15,23.0.162.21
+PL,PARCZEW,"",51.63,22.90,80.15.235.163
+US,CORTLANDTMANOR,NY,41.2893,-73.9009,184.26.44.38
+DK,VIBY,"",55.55,12.03,23.65.29.106
+RO,CAMPINA,"",45.13,25.73,88.221.93.157
+SI,KAMNIK,"",45.95,14.42,2.20.142.166
+DE,APOLDA,TH,51.02,11.50,92.122.207.179
+US,TWORIVERS,WI,44.2198,-87.5999,184.85.215.170
+SE,SAVSJO,F,57.40,14.67,107.14.32.228
+DE,NEUBURG,RP,48.98,8.25,2.22.61.102
+RO,BUFTEA,"",44.57,25.95,2.22.52.105
+GB,KEELE,EN,53.00,-2.28,88.221.87.112
+BG,SIMITLI,"",41.88,23.12,93.186.137.231
+US,FOUNTAININN,SC,34.6459,-82.2156,165.254.138.175
+AT,NEUSTADT,"",48.03,16.78,195.145.147.109
+IR,BUSHEHR,"",28.97,50.83,213.200.109.173
+US,FULTONDALE,AL,33.6060,-86.8244,184.28.127.55
+BE,KORTRIJK,"",50.83,3.27,23.62.100.152
+US,KENLY,NC,35.6072,-78.1393,23.79.240.37
+DE,FREIBERG,SN,50.92,13.37,84.53.146.35
+JP,SHIBUYA,13,35.66,139.70,72.246.184.89
+PH,BACOLOD,"",10.67,122.95,58.71.107.116
+US,ELMONT,NY,40.7013,-73.7074,184.26.44.42
+PL,SKIERNIEWICE,"",51.97,20.15,2.22.52.109
+NP,POKHARA,"",28.23,83.98,23.76.205.111
+MK,BITOLA,"",41.03,21.34,23.62.237.138
+US,HANCEVILLE,AL,34.0311,-86.8105,72.246.247.30
+US,GUYTON,GA,32.3167,-81.3986,184.51.35.215
+TH,HONG,"",18.43,99.45,92.122.188.161
+CH,RHEINFELDEN,"",47.55,7.78,23.14.94.228
+US,JEROME,ID,42.7238,-114.3385,67.131.104.14
+US,HINESVILLE,GA,31.8475,-81.5964,23.79.240.48
+IR,IRANSHAHR,"",28.95,58.88,107.14.32.228
+NZ,GISBORNE,"",-38.65,178.00,203.96.118.165
+US,IMMOKALEE,FL,26.3154,-81.2708,23.215.15.9
+US,JOPPA,MD,39.4408,-76.3547,184.27.45.157
+US,OLDWESTBURY,NY,40.7854,-73.596,184.26.44.38
+US,DALHART,TX,36.2600,-102.5337,23.215.15.22
+DE,ANSBACH,BY,49.30,10.58,80.157.150.192
+AT,DRAU,"",46.58,14.00,195.145.147.101
+DE,TORGELOW,BB,52.75,13.97,195.145.147.108
+JP,TOYOHASHI,23,34.77,137.38,23.61.250.108
+JP,KUROSAWA,20,35.85,137.63,23.15.1.67
+RU,ZVEREVA,"",46.10,47.70,213.155.156.212
+US,SOUTHWILLIAMSON,KY,37.6621,-82.2917,184.28.17.55
+FI,HYVINKAA,"",60.63,24.87,184.150.187.108
+IT,SANVINCENZO,"",43.10,10.53,2.18.240.114
+US,ELDRIDGE,IA,41.6660,-90.5607,23.79.240.47
+US,WISCONSINDELLS,WI,43.6772,-89.746,23.63.227.227
+US,COBLESKILL,NY,42.6995,-74.5108,165.254.48.155
+CN,CHUNAN,ZJ,29.60,119.02,72.246.191.16
+RO,TOPLITA,"",45.05,24.77,92.122.188.161
+US,HILLSIDE,NJ,40.6961,-74.2294,184.26.44.40
+US,BIDDEFORD,ME,43.4906,-70.5283,165.254.48.155
+US,HARRODSBURG,KY,37.7856,-84.8966,209.18.46.205
+US,PORTOLA,CA,39.8755,-120.4492,63.233.61.159
+US,PETOSKEY,MI,45.3433,-84.8827,96.17.180.177
+US,SHAWAFB,SC,33.9749,-80.463,209.18.41.27
+RO,TARNAVENI,"",46.33,24.28,77.67.27.250
+AT,HEILIGENKREUZ,"",48.05,16.13,195.145.147.101
+US,AFTON,WY,42.6962,-110.9188,173.223.52.70
+US,THOMPSONSSTATION,TN,35.8120,-86.9532,23.79.240.36
+JP,NISHINO,04,38.63,141.20,23.3.74.112
+TH,KONG,"",16.93,99.97,23.14.94.228
+CH,FLIMS,"",46.83,9.28,193.247.167.211
+US,CHAGRINFALLS,OH,41.4475,-81.4018,107.14.38.224
+US,SMARTT,TN,35.6544,-85.8274,23.79.240.37
+DE,LOHNE,HE,51.18,9.27,92.122.207.179
+CH,MONTHEY,"",46.25,6.95,92.122.189.85
+US,SHIPPENSBURG,PA,40.0414,-77.4967,205.185.195.170
+AT,HUBEN,"",46.93,12.57,195.145.147.107
+FR,AUBIGNY,"",48.60,2.68,2.16.117.197
+FR,SAINTMEDARDENJALLES,"",44.90,-0.73,2.16.117.212
+JP,MAKINO,27,34.35,135.28,72.246.184.84
+FR,CAMBRIN,"",50.50,2.73,2.16.117.212
+CZ,MEZIBORI,"",50.62,13.60,23.74.24.66
+IR,PARDIS,"",30.28,48.47,213.155.156.208
+IR,SABZ,"",37.43,47.82,96.17.182.136
+DK,VEJEN,"",55.48,9.15,2.21.240.40
+US,SPENCERPORT,NY,43.1672,-77.8292,23.74.8.24
+US,HICKORYHILLS,IL,41.7253,-87.8309,23.67.60.220
+RU,MICHURINSKIY,"",53.27,34.23,80.239.222.167
+US,BRADDOCK,PA,40.4039,-79.8613,184.28.17.55
+FR,BELLEY,"",48.30,4.15,2.16.117.185
+US,VILLANOVA,PA,40.0374,-75.3509,23.67.242.139
+US,WAUCHULA,FL,27.5499,-81.8315,23.33.186.134
+KZ,USHARAL,"",44.23,76.85,2.21.240.61
+CZ,PECKY,"",50.09,15.03,195.27.155.193
+DE,WOLF,HE,50.32,9.08,80.157.170.154
+DE,NORDHAUSEN,BW,49.10,9.11,195.95.193.132
+UA,ZHYTOMYR,"",50.25,28.67,23.14.94.214
+US,IJAMSVILLE,MD,39.3307,-77.3133,23.192.161.21
+US,FRIDAYHARBOR,WA,48.5377,-123.0836,23.212.59.85
+JP,NIKKO,09,36.75,139.62,96.7.251.95
+IN,VELLORE,TN,12.93,79.13,23.205.118.106
+AU,TUGGERANONG,ACT,-35.43,149.15,104.72.70.96
+US,MOUNTZION,IL,39.7516,-88.8516,23.67.60.220
+US,OLDORCHARDBEACH,ME,43.5280,-70.3929,107.14.38.218
+US,CLINTONVILLE,WI,44.6424,-88.7405,184.85.215.165
+RO,POPESTILEORDENI,"",44.38,26.17,81.196.26.198
+FR,PONTCHARRA,"",45.87,4.48,2.16.117.212
+NO,ALESUND,"",62.47,6.15,217.212.227.31
+US,COLLINGSWOOD,NJ,39.9152,-75.0615,184.26.44.42
+US,RICHTONPARK,IL,41.4788,-87.7394,23.67.60.222
+US,OSAWATOMIE,KS,38.4532,-94.9928,69.31.59.63
+IN,PUSA,BR,25.98,85.68,213.248.108.233
+US,ROSENBERG,TX,29.5301,-95.8155,23.215.15.22
+BR,JURUENA,MT,-12.85,-58.93,200.174.107.50
+FR,REALMONT,"",43.78,2.20,2.16.117.212
+US,PERRYHALL,MD,39.4067,-76.447,184.28.17.76
+IT,ROMANO,"",45.38,7.87,46.33.73.209
+FR,GOUSSAINVILLE,"",49.02,2.47,2.16.117.185
+BE,WAVER,"",50.93,4.10,23.62.100.154
+CA,PORTCOQUITLAM,BC,49.27,-122.78,96.17.180.166
+DE,HEIDENHEIM,BY,49.02,10.75,23.74.24.69
+US,WAPAKONETA,OH,40.5656,-84.1367,107.14.32.228
+CH,AARAU,"",47.38,8.05,88.221.93.150
+FR,CRE,"",47.68,-0.15,23.200.87.58
+PH,TACLOBAN,"",11.25,125.00,202.78.83.170
+DE,HOLTER,NW,51.77,8.12,195.145.147.108
+DO,BONAO,"",18.93,-70.42,72.246.65.38
+IN,REWA,MP,24.53,81.30,23.205.118.109
+US,BROWNSBORO,AL,34.7068,-86.4742,23.220.100.223
+BR,JANDIRA,SP,-23.52,-46.90,187.59.4.154
+TR,KARTAL,"",39.82,35.65,80.15.235.148
+US,NORTHPROVIDENCE,RI,41.8539,-71.4734,72.247.10.241
+US,NORTHVERSAILLES,PA,40.3802,-79.8167,23.192.161.21
+US,BRADLEY,CA,35.8301,-120.9932,23.215.15.22
+US,BLOOMER,WI,45.1062,-91.4948,23.63.227.214
+US,TELFORD,PA,40.3260,-75.3739,184.26.44.42
+AT,RANKWEIL,"",47.28,9.65,2.16.217.206
+DE,RHEINE,NW,52.28,7.45,2.22.61.102
+DE,BODEN,RP,50.47,7.85,92.122.215.89
+US,FORTWASHINGTON,PA,40.1333,-75.2109,96.17.180.166
+PL,JAWOROWA,"",52.13,20.95,80.157.149.181
+US,DEERLODGE,MT,46.3570,-112.7713,23.63.227.214
+CZ,DLOUHA,"",50.18,13.03,195.27.155.193
+US,LOUISA,KY,37.9848,-82.5857,184.28.17.76
+AR,SANTALUCIA,"",-33.87,-59.87,200.123.194.62
+IN,SOLAN,HP,30.92,77.12,96.17.182.127
+US,DANSVILLE,NY,42.5670,-77.738,107.14.38.227
+CN,SONGJIANG,SH,31.01,121.23,72.246.191.19
+AR,INGENIEROLUIGGI,"",-35.42,-64.48,200.123.201.219
+US,CENTERTON,AR,36.3689,-94.3208,23.215.15.22
+PH,MALACANANG,"",11.40,122.05,58.71.107.119
+US,MALTA,IL,41.8958,-88.8827,23.67.60.223
+FR,RAMONVILLESAINTAGNE,"",43.55,1.47,81.52.201.101
+IN,PAREL,MH,19.00,72.83,124.124.252.160
+RU,OR,"",51.20,58.70,80.239.222.167
+FR,CHEVRIERES,"",49.35,2.68,2.16.117.212
+NG,UYO,"",5.05,7.93,2.20.44.118
+JP,KANI,21,35.43,137.07,23.3.104.20
+US,RAYMOND,MS,32.2288,-90.4476,23.212.53.64
+ID,SENAYAN,"",-6.23,106.78,96.17.180.155
+RU,MIRNY,"",45.55,38.91,213.155.156.207
+AT,GROSSPETERSDORF,"",47.23,16.32,195.145.147.107
+AR,ALEJANDROKORN,"",-34.98,-58.38,190.98.167.230
+UA,IVANOV,"",49.48,28.35,46.33.70.97
+US,EPHRAIM,UT,39.3528,-111.5432,23.216.10.78
+AT,RANNERSDORF,"",48.12,16.47,195.145.147.107
+JP,KAWASAKI,14,35.52,139.72,118.155.230.132
+CA,BEACHBURG,ON,45.73,-76.85,72.246.43.237
+IN,HIMATNAGAR,GJ,23.60,72.95,117.239.189.111
+FR,CHEVREUSE,"",48.70,2.05,2.16.117.185
+IL,EINHAMIFRATZ,"",32.90,35.10,82.102.137.137
+RU,MAIKOP,"",44.61,40.11,80.239.237.93
+FR,BOULOGNESURMER,"",50.72,1.62,2.16.117.185
+US,GALVA,KS,38.3914,-97.5376,23.215.15.9
+US,REPUBLIC,MO,37.1404,-93.5188,23.77.234.35
+IR,CHAHARMAHAL,"",29.61,50.76,184.25.157.162
+DE,ANDERNACH,RP,50.43,7.40,23.14.94.228
+BR,PORTOVELHO,SP,-24.03,-46.72,187.59.4.147
+IT,VITO,"",38.13,15.70,96.17.180.155
+LT,VISAGINAS,"",55.60,26.42,92.122.189.85
+AT,KEMATEN,"",48.03,14.75,195.145.147.101
+PL,WARKA,"",51.78,21.20,2.22.52.105
+CI,BOUAKE,"",7.68,-5.03,23.0.162.40
+IR,MAHAN,"",34.18,48.21,184.25.157.162
+DK,HAARLEV,"",55.35,12.25,23.65.29.93
+CZ,BZENEC,"",48.98,17.27,195.27.155.188
+FR,CHATEAUDUN,"",48.08,1.33,2.16.117.200
+RO,CARACAL,"",45.02,24.88,88.221.93.150
+US,BARAGA,MI,46.8110,-88.5098,107.14.32.228
+CA,SALMONARM,BC,50.70,-119.28,184.27.179.159
+CA,PORTHARDY,BC,50.72,-127.50,184.27.179.159
+DE,FLORENBERG,HE,50.52,9.72,194.25.95.214
+TH,SAMUTPRAKAN,"",13.60,100.60,203.153.50.80
+IT,CESENA,"",44.14,12.25,2.20.142.166
+US,CARNEY,MI,45.5790,-87.5356,23.79.240.48
+CN,HEIHE,HL,50.27,127.47,184.84.239.175
+US,WADENA,MN,46.4558,-95.094,65.113.249.11
+FR,PONTEVEQUE,"",45.53,4.92,2.16.117.212
+PL,RADOSLAW,"",51.77,16.48,2.22.52.101
diff --git a/tests/large/sample/cp.csv b/tests/large/sample/cp.csv
new file mode 100644
index 00000000..57d0074c
--- /dev/null
+++ b/tests/large/sample/cp.csv
@@ -0,0 +1,3 @@
+113982
+277253
+323114
diff --git a/tests/large/sample/id.csv b/tests/large/sample/id.csv
new file mode 100644
index 00000000..23b3c04c
--- /dev/null
+++ b/tests/large/sample/id.csv
@@ -0,0 +1,100 @@
+ea7211754ec15b845ca906
+eab2c41754ec15b8124f9916-a
+852612254ec15b81bbad91c
+1007f54ec15b81341de68
+eae2ce1754ec15b810aac129
+ea12241754ec15b810397ca
+2a3de1754ec15b8f18617f
+ea82311754ec15b82e9bee9
+ea7291754ec15b876f64d47-a
+1007f54ec15b838d595c2
+5dc1c11754ec15b87524
+eae2401754ec15b81e64092c
+3cbe411754ec15b81a9f8da
+abc3361754ec15b81a873d5
+ea7211754ec15b8231359ea-a
+2c65421754ec15b8261e20a
+f62d18b854ec15b899dd00a
+ea6276054ec15b870c0e59-a
+ea92341754ec15b87b147af
+1682446854ec15b8c2ef917
+ea424f1754ec15b82fd3c688
+ea7211754ec15b823135fc9-a
+ea92c11754ec15b8c577e60-a
+ea82311754ec15b84122466f-a
+eac2281754ec15b85354799
+ea7211754ec15b845ca8ff
+ea62491754ec15b866af125-a
+5dc1c11754ec15b8760c-a
+ea424f1754ec15b83f96806-a
+798e6ac54ec15b8205f877d
+8e53e2ac54ec15b83a2d44c8
+8e53e2ac54ec15b81779f6c8
+ea62d11754ec15b84047f3b6
+545714254ec15b8261ef911-a
+eae2ce1754ec15b810aac119
+1007f54ec15b8368562a
+eac23b1754ec15b81a2f05
+eae2ce1754ec15b81f00403a
+4032d1754ec15b84ef8f070
+1ff7201754ec15b81ca5de59
+eaf2251754ec15b847c3981
+eae2ce1754ec15b81f004033
+eab22b1754ec15b837f350c
+abc3361754ec15b81a875bd
+ea2361754ec15b84b66c3d6
+3863de1754ec15b840a41b6f-a
+1007f54ec15b81ca5e0f4
+ea92311754ec15b81ba91fa4-a
+1007f54ec15b8101f30ec
+d47454b854ec15b83eeffc7
+a725d41754ec15b81c7c5873
+1007f54ec15b83757152a
+1007f54ec15b837f5277
+ea12cc1754ec15b835e609e-a
+ea2d31754ec15b88b1a11f
+eab2d31754ec15b815a3d8a7-a
+ea32251754ec15b838d595c2
+ea42d21754ec15b822711d5f
+eac23b1754ec15b8f1cb626
+1007f54ec15b822710753
+3317a1754ec15b81b803928-a
+c7872e1754ec15b82a4218a9-a
+3317a1754ec15b81b80398d-a
+eac23b1754ec15b8652720
+a39df1754ec15b81571b1c3-a
+c7872e1754ec15b81fa5244e
+ea7211754ec15b82313610e
+ea2d31754ec15b8133f2c3c
+13b5e2ac54ec15b8135fe4-a
+abc3361754ec15b81a874cc
+ea82361754ec15b8227494
+82db481754ec15b82c1f1327-a
+d6b471754ec15b8210be9a3-a
+ea723b1754ec15b85c05e90f-a
+ea92341754ec15b87b147a3
+9ec34b1754ec15b8b132d9b-a
+b4e14a1754ec15b81aea0e6c-a
+1682446854ec15b8c2ef845-a
+eaf2dfad54ec15b87630821
+ea7291754ec15b81ddfa729
+ea92c11754ec15b8c565b38
+1ff7201754ec15b81ca5d134
+ea12d61754ec15b8185ea12c
+ea12d61754ec15b8185efa94
+8e53e2ac54ec15b81779f6b3
+82db481754ec15b82c1f0940-a
+ea6261754ec15b8277ca2c6
+ead22e1754ec15b8618713-a
+ea2411754ec15b869fc10a
+8eaa436854ec15b812d62f36
+ea6261754ec15b81840a2f4
+3863de1754ec15b840a39abc
+798e6ac54ec15b832b8f4e
+7443211754ec15b83757152a
+ea7211754ec15b845ca8f0
+218446854ec15b82b6381f9-a
+9ec34b1754ec15b81591ba99
+c5e23a1754ec15b820275329
+ea92351754ec15b821848589
+eab2d31754ec15b815a3f23b
diff --git a/tests/large/sample/ip.csv b/tests/large/sample/ip.csv
new file mode 100644
index 00000000..cfe90552
--- /dev/null
+++ b/tests/large/sample/ip.csv
@@ -0,0 +1,100 @@
+23.1.114.234
+23.196.178.234
+2.18.38.133
+23.206.226.234
+23.36.18.234
+23.222.163.2
+23.49.130.234
+23.9.114.234
+23.193.193.93
+23.64.226.234
+23.65.190.60
+23.54.195.171
+23.66.101.44
+184.24.45.246
+96.7.98.234
+23.52.146.234
+104.68.130.22
+23.79.66.234
+23.193.146.234
+23.40.194.234
+23.73.98.234
+172.230.152.7
+172.226.83.142
+23.209.98.234
+2.20.87.84
+23.59.194.234
+23.13.50.64
+23.32.247.31
+23.37.242.234
+23.43.178.234
+23.54.2.234
+23.222.99.56
+23.49.146.234
+184.84.116.212
+23.212.37.167
+23.204.18.234
+23.211.2.234
+23.211.178.234
+23.37.50.234
+23.210.66.234
+23.10.23.51
+23.46.135.199
+23.223.57.10
+172.226.181.19
+23.54.130.234
+23.72.219.130
+23.7.180.214
+23.59.114.234
+23.75.195.158
+23.74.225.180
+173.223.242.234
+23.214.18.234
+23.6.98.234
+23.46.210.234
+23.65.2.234
+104.67.170.142
+23.33.67.116
+104.68.8.33
+23.58.226.197
+23.53.146.234
+23.77.18.234
+23.63.195.40
+2.20.98.234
+96.16.220.139
+23.50.146.234
+184.51.208.185
+23.201.210.234
+23.41.0.20
+23.194.50.234
+23.214.154.131
+95.100.126.200
+172.229.194.234
+23.50.82.234
+23.4.132.102
+23.79.99.50
+23.218.215.93
+23.203.2.234
+23.57.210.234
+23.195.122.147
+23.64.114.13
+23.37.151.160
+23.53.210.234
+172.231.252.196
+104.73.32.231
+23.43.66.234
+23.197.11.186
+23.73.162.234
+23.51.51.183
+23.220.18.234
+104.66.212.185
+23.73.2.234
+23.63.84.195
+23.212.200.244
+2.16.47.42
+172.233.88.222
+23.49.226.234
+23.74.82.234
+23.76.178.234
+23.212.226.234
+23.36.34.234
diff --git a/tests/large/sample/replay b/tests/large/sample/replay
new file mode 100755
index 00000000..b906dc98
--- /dev/null
+++ b/tests/large/sample/replay
@@ -0,0 +1,12 @@
+2014-01-04 20:00:00 WINDBAG Event 1 of 12 randint @@integer
+2014-01-04 20:00:01 WINDBAG Event 2 of 12 randint @@integer
+2014-01-04 20:00:02 WINDBAG Event 3 of 12 randint @@integer
+2014-01-04 20:00:03 WINDBAG Event 4 of 12 randint @@integer
+2014-01-04 20:00:03 WINDBAG Event 5 of 12 randint @@integer
+2014-01-04 20:00:04 WINDBAG Event 6 of 12 randint @@integer
+2014-01-04 20:00:05 WINDBAG Event 7 of 12 randint @@integer
+2014-01-04 20:00:06 WINDBAG Event 8 of 12 randint @@integer
+2014-01-04 20:00:08 WINDBAG Event 9 of 12 randint @@integer
+2014-01-04 20:00:20 WINDBAG Event 10 of 12 randint @@integer
+2014-01-04 20:00:21 WINDBAG Event 11 of 12 randint @@integer
+2014-01-04 20:00:21 WINDBAG Event 12 of 12 randint @@integer
diff --git a/tests/large/sample/sample b/tests/large/sample/sample
new file mode 100755
index 00000000..b906dc98
--- /dev/null
+++ b/tests/large/sample/sample
@@ -0,0 +1,12 @@
+2014-01-04 20:00:00 WINDBAG Event 1 of 12 randint @@integer
+2014-01-04 20:00:01 WINDBAG Event 2 of 12 randint @@integer
+2014-01-04 20:00:02 WINDBAG Event 3 of 12 randint @@integer
+2014-01-04 20:00:03 WINDBAG Event 4 of 12 randint @@integer
+2014-01-04 20:00:03 WINDBAG Event 5 of 12 randint @@integer
+2014-01-04 20:00:04 WINDBAG Event 6 of 12 randint @@integer
+2014-01-04 20:00:05 WINDBAG Event 7 of 12 randint @@integer
+2014-01-04 20:00:06 WINDBAG Event 8 of 12 randint @@integer
+2014-01-04 20:00:08 WINDBAG Event 9 of 12 randint @@integer
+2014-01-04 20:00:20 WINDBAG Event 10 of 12 randint @@integer
+2014-01-04 20:00:21 WINDBAG Event 11 of 12 randint @@integer
+2014-01-04 20:00:21 WINDBAG Event 12 of 12 randint @@integer
diff --git a/tests/large/sample/timeorder.csv b/tests/large/sample/timeorder.csv
new file mode 100644
index 00000000..72e2fc31
--- /dev/null
+++ b/tests/large/sample/timeorder.csv
@@ -0,0 +1,11 @@
+_time,_raw,index,host,source,sourcetype
+2015-08-18T16:28:54.695-0700,"127.0.0.1 - admin [18/Aug/2015:16:28:54.695 -0700] ""GET /en-US/api/shelper?snippet=true&snippetEmbedJS=false&namespace=search&search=search+index%3D_internal+%7C+fields+_time%2C+_raw%2C+index%2C+host%2C+source%2C+sourcetype+&useTypeahead=true&useAssistant=true&showCommandHelp=true&showCommandHistory=true&showFieldInfo=false&_=1439940537886 HTTP/1.1"" 200 994 ""https://host5.foobar.com:8000/en-US/app/search/search?q=search%20index%3D_internal%20%7C%20fields%20_time%2C%20_raw%2C%20index%2C%20host%2C%20source%2C%20sourcetype&sid=1439940529.1846224&earliest=&latest="" ""Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.132 Safari/537.36"" - 55d3bfb6b17f7ff8270d50 33ms",_internal,host5.foobar.com,/usr/local/bamboo/itsi-demo/local/splunk/var/log/splunk/web_access.log,splunk_web_access
+2015-08-18T16:28:54.569-0700,"2015-08-18 16:28:54,569 INFO streams_utils:24 - utils::readAsJson:: /usr/local/bamboo/itsi-demo/local/splunk/etc/apps/splunk_app_stream/local/apps",_internal,host5.foobar.com,/usr/local/bamboo/itsi-demo/local/splunk/var/log/splunk/splunk_app_stream.log,splunk_app_stream.log
+2015-08-18T16:28:54.568-0700,"2015-08-18 16:28:54,568 INFO streams_utils:74 - create dir /usr/local/bamboo/itsi-demo/local/splunk/etc/apps/splunk_app_stream/local/",_internal,host5.foobar.com,/usr/local/bamboo/itsi-demo/local/splunk/var/log/splunk/splunk_app_stream.log,splunk_app_stream.log
+2015-08-18T16:28:54.564-0700,"127.0.0.1 - - [18/Aug/2015:16:28:54.564 -0700] ""GET /en-us/custom/splunk_app_stream/ping/ HTTP/1.1"" 200 311 """" """" - 55d3bfb6907f7ff805f710 5ms",_internal,host5.foobar.com,/usr/local/bamboo/itsi-demo/local/splunk/var/log/splunk/web_access.log,splunk_web_access
+2015-08-18T16:28:52.798-0700,"10.160.255.115 - admin [18/Aug/2015:16:28:52.798 -0700] ""GET /en-US/splunkd/__raw/servicesNS/nobody/search/search/jobs/1439940529.1846224/summary?output_mode=json&min_freq=0&_=1439940537880 HTTP/1.1"" 200 503 ""https://host5.foobar.com:8000/en-US/app/search/search?q=search%20index%3D_internal%20%7C%20fields%20_time%2C%20_raw%2C%20index%2C%20host%2C%20source%2C%20sourcetype&sid=1439940529.1846224&earliest=&latest="" ""Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.132 Safari/537.36"" - 9f802569d5c3d77d468e897d34f8969f 6ms",_internal,host5.foobar.com,/usr/local/bamboo/itsi-demo/local/splunk/var/log/splunk/splunkd_ui_access.log,splunkd_ui_access
+2015-08-18T16:28:52.798-0700,"10.160.255.115 - admin [18/Aug/2015:16:28:52.798 -0700] ""GET /en-US/splunkd/__raw/services/search/jobs/1439940529.1846224/timeline?offset=0&count=1000&_=1439940537881 HTTP/1.1"" 200 349 ""https://host5.foobar.com:8000/en-US/app/search/search?q=search%20index%3D_internal%20%7C%20fields%20_time%2C%20_raw%2C%20index%2C%20host%2C%20source%2C%20sourcetype&sid=1439940529.1846224&earliest=&latest="" ""Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.132 Safari/537.36"" - 9f802569d5c3d77d468e897d34f8969f 4ms",_internal,host5.foobar.com,/usr/local/bamboo/itsi-demo/local/splunk/var/log/splunk/splunkd_ui_access.log,splunkd_ui_access
+2015-08-18T16:28:52.754-0700,"10.160.255.115 - admin [18/Aug/2015:16:28:52.754 -0700] ""GET /en-US/splunkd/__raw/servicesNS/nobody/search/search/jobs/1439940529.1846224?output_mode=json&_=1439940537879 HTTP/1.1"" 200 1543 ""https://host5.foobar.com:8000/en-US/app/search/search?q=search%20index%3D_internal%20%7C%20fields%20_time%2C%20_raw%2C%20index%2C%20host%2C%20source%2C%20sourcetype&sid=1439940529.1846224&earliest=&latest="" ""Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.132 Safari/537.36"" - 9f802569d5c3d77d468e897d34f8969f 4ms",_internal,host5.foobar.com,/usr/local/bamboo/itsi-demo/local/splunk/var/log/splunk/splunkd_ui_access.log,splunkd_ui_access
+2015-08-18T16:28:52.270-0700,"2015-08-18 16:28:52,270 ERROR pid=16324 tid=MainThread file=__init__.py:execute:957 | Execution failed: [HTTP 401] Client is not authenticated
+2015-08-18T16:28:52.268-0700,"127.0.0.1 - - [18/Aug/2015:16:28:52.268 -0700] ""GET /services/shcluster/config/config HTTP/1.0"" 401 148 - - - 0ms",_internal,host5.foobar.com,/usr/local/bamboo/itsi-demo/local/splunk/var/log/splunk/splunkd_access.log,splunkd_access
+2015-08-18T16:28:52.247-0700,"2015-08-18 16:28:52,247 INFO pid=16324 tid=MainThread file=__init__.py:execute:906 | Execute called",_internal,host5.foobar.com,/usr/local/bamboo/itsi-demo/local/splunk/var/log/splunk/python_modular_input.log,python_modular_input
diff --git a/tests/large/sample/tokenreplacement.sample b/tests/large/sample/tokenreplacement.sample
new file mode 100644
index 00000000..59dbc485
--- /dev/null
+++ b/tests/large/sample/tokenreplacement.sample
@@ -0,0 +1,10 @@
+{"type":"cloud_monitor","format":"default","version":"1.0","id":"ea7211754ec15b845ca906","start":"1424758200.997","cp":"113982","message":{"reqQuery":"cmd%3d_dummyaccessrequest-submit%26dispatch%3d5885d80a13c0db1f8e263663d3faee8da8649a435e198e44a05ba053bc68d12e","reqLen":68,"reqCT":"application%2fjson%3b%20charset%3dUTF-8","proto":"http","protoVer":"1.1","status":"301","cliIP":"999.254.16.5","reqPort":"80","reqHost":"www.dummycompanytest.com","reqMethod":"GET","reqPath":"%2f","respLen":"0","bytes":"0","UA":"PowerShell%20Script","fwdHost":"origin-www.dummycompanytest.com.akadns.net"},"netPerf":{"downloadTime":"2","lastMileRTT":"22","cacheStatus":"0","firstByte":"0","lastByte":"1","asnum":"25667","edgeIP":"23.74.2.12"},"geo":{"country":"US","region":"GA","city":"ATLANTA","lat":"33.7486","long":"-84.3884"},"network":{"edgeIP":"23.74.2.12","asnum":"25667","network":"","networkType":""},"akadebug":{"Ak_IP":"23.1.114.234","akam-server-type":"Production","current-time":"1424758200","forward-origin-ip":"10.10.10.10","end-user-ip":"999.254.16.5","akamai-request-id":"45ca906","cpcode":"113982","origin-timeout":"no"},"ppcustomdata":{"hostheader":"","cmd":"","receiver_id":"","ADS":""},"reqHdr":{"accEnc":"gzip","referer":"https://www.splunk.com","cookie":"firebrowser","conn":"Keep-Alive"}}
+{"type":"cloud_monitor","format":"default","version":"1.0","id":"ea7211754ec15b845ca906","start":"1424758200.997","cp":"113982","message":{"reqQuery":"cmd%3d_dummyaccessrequest-submit%26dispatch%3d5885d80a13c0db1f8e263663d3faee8da8649a435e198e44a05ba053bc68d12e","reqLen":68,"reqCT":"application%2fjson%3b%20charset%3dUTF-8","proto":"http","protoVer":"1.1","status":"301","cliIP":"999.254.16.5","reqPort":"80","reqHost":"www.dummycompanytest.com","reqMethod":"GET","reqPath":"%2f","respLen":"0","bytes":"0","UA":"PowerShell%20Script","fwdHost":"origin-www.dummycompanytest.com.akadns.net"},"netPerf":{"downloadTime":"2","lastMileRTT":"22","cacheStatus":"0","firstByte":"0","lastByte":"1","asnum":"25667","edgeIP":"23.74.2.12"},"geo":{"country":"US","region":"GA","city":"ATLANTA","lat":"33.7486","long":"-84.3884"},"network":{"edgeIP":"23.74.2.12","asnum":"25667","network":"","networkType":""},"akadebug":{"Ak_IP":"23.1.114.234","akam-server-type":"Production","current-time":"1424758200","forward-origin-ip":"10.10.10.10","end-user-ip":"999.254.16.5","akamai-request-id":"45ca906","cpcode":"113982","origin-timeout":"no"},"ppcustomdata":{"hostheader":"","cmd":"","receiver_id":"","ADS":""},"reqHdr":{"accEnc":"gzip","referer":"https://www.splunk.com","cookie":"firebrowser","conn":"Keep-Alive"}}
+{"type":"cloud_monitor","format":"default","version":"1.0","id":"ea7211754ec15b845ca906","start":"1424758200.997","cp":"113982","message":{"reqQuery":"cmd%3d_dummyaccessrequest-submit%26dispatch%3d5885d80a13c0db1f8e263663d3faee8da8649a435e198e44a05ba053bc68d12e","reqLen":68,"reqCT":"application%2fjson%3b%20charset%3dUTF-8","proto":"http","protoVer":"1.1","status":"301","cliIP":"999.254.16.5","reqPort":"80","reqHost":"www.dummycompanytest.com","reqMethod":"GET","reqPath":"%2f","respLen":"0","bytes":"0","UA":"PowerShell%20Script","fwdHost":"origin-www.dummycompanytest.com.akadns.net"},"netPerf":{"downloadTime":"2","lastMileRTT":"22","cacheStatus":"0","firstByte":"0","lastByte":"1","asnum":"25667","edgeIP":"23.74.2.12"},"geo":{"country":"US","region":"GA","city":"ATLANTA","lat":"33.7486","long":"-84.3884"},"network":{"edgeIP":"23.74.2.12","asnum":"25667","network":"","networkType":""},"akadebug":{"Ak_IP":"23.1.114.234","akam-server-type":"Production","current-time":"1424758200","forward-origin-ip":"10.10.10.10","end-user-ip":"999.254.16.5","akamai-request-id":"45ca906","cpcode":"113982","origin-timeout":"no"},"ppcustomdata":{"hostheader":"","cmd":"","receiver_id":"","ADS":""},"reqHdr":{"accEnc":"gzip","referer":"https://www.splunk.com","cookie":"firebrowser","conn":"Keep-Alive"}}
+{"type":"cloud_monitor","format":"default","version":"1.0","id":"ea7211754ec15b845ca906","start":"1424758200.997","cp":"113982","message":{"reqQuery":"cmd%3d_dummyaccessrequest-submit%26dispatch%3d5885d80a13c0db1f8e263663d3faee8da8649a435e198e44a05ba053bc68d12e","reqLen":68,"reqCT":"application%2fjson%3b%20charset%3dUTF-8","proto":"http","protoVer":"1.1","status":"301","cliIP":"999.254.16.5","reqPort":"80","reqHost":"www.dummycompanytest.com","reqMethod":"GET","reqPath":"%2f","respLen":"0","bytes":"0","UA":"PowerShell%20Script","fwdHost":"origin-www.dummycompanytest.com.akadns.net"},"netPerf":{"downloadTime":"2","lastMileRTT":"22","cacheStatus":"0","firstByte":"0","lastByte":"1","asnum":"25667","edgeIP":"23.74.2.12"},"geo":{"country":"US","region":"GA","city":"ATLANTA","lat":"33.7486","long":"-84.3884"},"network":{"edgeIP":"23.74.2.12","asnum":"25667","network":"","networkType":""},"akadebug":{"Ak_IP":"23.1.114.234","akam-server-type":"Production","current-time":"1424758200","forward-origin-ip":"10.10.10.10","end-user-ip":"999.254.16.5","akamai-request-id":"45ca906","cpcode":"113982","origin-timeout":"no"},"ppcustomdata":{"hostheader":"","cmd":"","receiver_id":"","ADS":""},"reqHdr":{"accEnc":"gzip","referer":"https://www.splunk.com","cookie":"firebrowser","conn":"Keep-Alive"}}
+{"type":"cloud_monitor","format":"default","version":"1.0","id":"ea7211754ec15b845ca906","start":"1424758200.997","cp":"113982","message":{"reqQuery":"cmd%3d_dummyaccessrequest-submit%26dispatch%3d5885d80a13c0db1f8e263663d3faee8da8649a435e198e44a05ba053bc68d12e","reqLen":68,"reqCT":"application%2fjson%3b%20charset%3dUTF-8","proto":"http","protoVer":"1.1","status":"301","cliIP":"999.254.16.5","reqPort":"80","reqHost":"www.dummycompanytest.com","reqMethod":"GET","reqPath":"%2f","respLen":"0","bytes":"0","UA":"PowerShell%20Script","fwdHost":"origin-www.dummycompanytest.com.akadns.net"},"netPerf":{"downloadTime":"2","lastMileRTT":"22","cacheStatus":"0","firstByte":"0","lastByte":"1","asnum":"25667","edgeIP":"23.74.2.12"},"geo":{"country":"US","region":"GA","city":"ATLANTA","lat":"33.7486","long":"-84.3884"},"network":{"edgeIP":"23.74.2.12","asnum":"25667","network":"","networkType":""},"akadebug":{"Ak_IP":"23.1.114.234","akam-server-type":"Production","current-time":"1424758200","forward-origin-ip":"10.10.10.10","end-user-ip":"999.254.16.5","akamai-request-id":"45ca906","cpcode":"113982","origin-timeout":"no"},"ppcustomdata":{"hostheader":"","cmd":"","receiver_id":"","ADS":""},"reqHdr":{"accEnc":"gzip","referer":"https://www.splunk.com","cookie":"firebrowser","conn":"Keep-Alive"}}
+{"type":"cloud_monitor","format":"default","version":"1.0","id":"ea7211754ec15b845ca906","start":"1424758200.997","cp":"113982","message":{"reqQuery":"cmd%3d_dummyaccessrequest-submit%26dispatch%3d5885d80a13c0db1f8e263663d3faee8da8649a435e198e44a05ba053bc68d12e","reqLen":68,"reqCT":"application%2fjson%3b%20charset%3dUTF-8","proto":"http","protoVer":"1.1","status":"301","cliIP":"999.254.16.5","reqPort":"80","reqHost":"www.dummycompanytest.com","reqMethod":"GET","reqPath":"%2f","respLen":"0","bytes":"0","UA":"PowerShell%20Script","fwdHost":"origin-www.dummycompanytest.com.akadns.net"},"netPerf":{"downloadTime":"2","lastMileRTT":"22","cacheStatus":"0","firstByte":"0","lastByte":"1","asnum":"25667","edgeIP":"23.74.2.12"},"geo":{"country":"US","region":"GA","city":"ATLANTA","lat":"33.7486","long":"-84.3884"},"network":{"edgeIP":"23.74.2.12","asnum":"25667","network":"","networkType":""},"akadebug":{"Ak_IP":"23.1.114.234","akam-server-type":"Production","current-time":"1424758200","forward-origin-ip":"10.10.10.10","end-user-ip":"999.254.16.5","akamai-request-id":"45ca906","cpcode":"113982","origin-timeout":"no"},"ppcustomdata":{"hostheader":"","cmd":"","receiver_id":"","ADS":""},"reqHdr":{"accEnc":"gzip","referer":"https://www.splunk.com","cookie":"firebrowser","conn":"Keep-Alive"}}
+{"type":"cloud_monitor","format":"default","version":"1.0","id":"ea7211754ec15b845ca906","start":"1424758200.997","cp":"113982","message":{"reqQuery":"cmd%3d_dummyaccessrequest-submit%26dispatch%3d5885d80a13c0db1f8e263663d3faee8da8649a435e198e44a05ba053bc68d12e","reqLen":68,"reqCT":"application%2fjson%3b%20charset%3dUTF-8","proto":"http","protoVer":"1.1","status":"301","cliIP":"999.254.16.5","reqPort":"80","reqHost":"www.dummycompanytest.com","reqMethod":"GET","reqPath":"%2f","respLen":"0","bytes":"0","UA":"PowerShell%20Script","fwdHost":"origin-www.dummycompanytest.com.akadns.net"},"netPerf":{"downloadTime":"2","lastMileRTT":"22","cacheStatus":"0","firstByte":"0","lastByte":"1","asnum":"25667","edgeIP":"23.74.2.12"},"geo":{"country":"US","region":"GA","city":"ATLANTA","lat":"33.7486","long":"-84.3884"},"network":{"edgeIP":"23.74.2.12","asnum":"25667","network":"","networkType":""},"akadebug":{"Ak_IP":"23.1.114.234","akam-server-type":"Production","current-time":"1424758200","forward-origin-ip":"10.10.10.10","end-user-ip":"999.254.16.5","akamai-request-id":"45ca906","cpcode":"113982","origin-timeout":"no"},"ppcustomdata":{"hostheader":"","cmd":"","receiver_id":"","ADS":""},"reqHdr":{"accEnc":"gzip","referer":"https://www.splunk.com","cookie":"firebrowser","conn":"Keep-Alive"}}
+{"type":"cloud_monitor","format":"default","version":"1.0","id":"ea7211754ec15b845ca906","start":"1424758200.997","cp":"113982","message":{"reqQuery":"cmd%3d_dummyaccessrequest-submit%26dispatch%3d5885d80a13c0db1f8e263663d3faee8da8649a435e198e44a05ba053bc68d12e","reqLen":68,"reqCT":"application%2fjson%3b%20charset%3dUTF-8","proto":"http","protoVer":"1.1","status":"301","cliIP":"999.254.16.5","reqPort":"80","reqHost":"www.dummycompanytest.com","reqMethod":"GET","reqPath":"%2f","respLen":"0","bytes":"0","UA":"PowerShell%20Script","fwdHost":"origin-www.dummycompanytest.com.akadns.net"},"netPerf":{"downloadTime":"2","lastMileRTT":"22","cacheStatus":"0","firstByte":"0","lastByte":"1","asnum":"25667","edgeIP":"23.74.2.12"},"geo":{"country":"US","region":"GA","city":"ATLANTA","lat":"33.7486","long":"-84.3884"},"network":{"edgeIP":"23.74.2.12","asnum":"25667","network":"","networkType":""},"akadebug":{"Ak_IP":"23.1.114.234","akam-server-type":"Production","current-time":"1424758200","forward-origin-ip":"10.10.10.10","end-user-ip":"999.254.16.5","akamai-request-id":"45ca906","cpcode":"113982","origin-timeout":"no"},"ppcustomdata":{"hostheader":"","cmd":"","receiver_id":"","ADS":""},"reqHdr":{"accEnc":"gzip","referer":"https://www.splunk.com","cookie":"firebrowser","conn":"Keep-Alive"}}
+{"type":"cloud_monitor","format":"default","version":"1.0","id":"ea7211754ec15b845ca906","start":"1424758200.997","cp":"113982","message":{"reqQuery":"cmd%3d_dummyaccessrequest-submit%26dispatch%3d5885d80a13c0db1f8e263663d3faee8da8649a435e198e44a05ba053bc68d12e","reqLen":68,"reqCT":"application%2fjson%3b%20charset%3dUTF-8","proto":"http","protoVer":"1.1","status":"301","cliIP":"999.254.16.5","reqPort":"80","reqHost":"www.dummycompanytest.com","reqMethod":"GET","reqPath":"%2f","respLen":"0","bytes":"0","UA":"PowerShell%20Script","fwdHost":"origin-www.dummycompanytest.com.akadns.net"},"netPerf":{"downloadTime":"2","lastMileRTT":"22","cacheStatus":"0","firstByte":"0","lastByte":"1","asnum":"25667","edgeIP":"23.74.2.12"},"geo":{"country":"US","region":"GA","city":"ATLANTA","lat":"33.7486","long":"-84.3884"},"network":{"edgeIP":"23.74.2.12","asnum":"25667","network":"","networkType":""},"akadebug":{"Ak_IP":"23.1.114.234","akam-server-type":"Production","current-time":"1424758200","forward-origin-ip":"10.10.10.10","end-user-ip":"999.254.16.5","akamai-request-id":"45ca906","cpcode":"113982","origin-timeout":"no"},"ppcustomdata":{"hostheader":"","cmd":"","receiver_id":"","ADS":""},"reqHdr":{"accEnc":"gzip","referer":"https://www.splunk.com","cookie":"firebrowser","conn":"Keep-Alive"}}
+{"type":"cloud_monitor","format":"default","version":"1.0","id":"ea7211754ec15b845ca906","start":"1424758200.997","cp":"113982","message":{"reqQuery":"cmd%3d_dummyaccessrequest-submit%26dispatch%3d5885d80a13c0db1f8e263663d3faee8da8649a435e198e44a05ba053bc68d12e","reqLen":68,"reqCT":"application%2fjson%3b%20charset%3dUTF-8","proto":"http","protoVer":"1.1","status":"301","cliIP":"999.254.16.5","reqPort":"80","reqHost":"www.dummycompanytest.com","reqMethod":"GET","reqPath":"%2f","respLen":"0","bytes":"0","UA":"PowerShell%20Script","fwdHost":"origin-www.dummycompanytest.com.akadns.net"},"netPerf":{"downloadTime":"2","lastMileRTT":"22","cacheStatus":"0","firstByte":"0","lastByte":"1","asnum":"25667","edgeIP":"23.74.2.12"},"geo":{"country":"US","region":"GA","city":"ATLANTA","lat":"33.7486","long":"-84.3884"},"network":{"edgeIP":"23.74.2.12","asnum":"25667","network":"","networkType":""},"akadebug":{"Ak_IP":"23.1.114.234","akam-server-type":"Production","current-time":"1424758200","forward-origin-ip":"10.10.10.10","end-user-ip":"999.254.16.5","akamai-request-id":"45ca906","cpcode":"113982","origin-timeout":"no"},"ppcustomdata":{"hostheader":"","cmd":"","receiver_id":"","ADS":""},"reqHdr":{"accEnc":"gzip","referer":"https://www.splunk.com","cookie":"firebrowser","conn":"Keep-Alive"}}
diff --git a/tests/large/test_eventgen_orchestration.py b/tests/large/test_eventgen_orchestration.py
index d5bc7cbe..19d35da3 100644
--- a/tests/large/test_eventgen_orchestration.py
+++ b/tests/large/test_eventgen_orchestration.py
@@ -1,16 +1,18 @@
#!/usr/bin/env python
# encoding: utf-8
+import json
import os
import time
-import json
+from random import choice
+from string import ascii_lowercase
+
import pytest
import requests
from docker import APIClient
-from random import choice
-from string import ascii_lowercase
# Code to suppress insecure https warnings
from requests.packages.urllib3.exceptions import InsecureRequestWarning
+
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
FILE_DIR = os.path.dirname(os.path.realpath(__file__))
@@ -18,12 +20,14 @@
IMAGE_NAME = "eventgen:test"
NETWORK_NAME = "eg_network_test"
+
def generate_random_string():
return ''.join(choice(ascii_lowercase) for b in range(20))
+
def wait_for_response(url, timeout=60):
start, end = time.time(), time.time()
- while end-start < timeout:
+ while end - start < timeout:
try:
r = requests.get(url)
r.raise_for_status()
@@ -35,249 +39,260 @@ def wait_for_response(url, timeout=60):
@pytest.mark.large
class TestEventgenOrchestration(object):
- '''
- This test class is used to test the Docker image published as part of this repo.
- Specifically, this is testing:
- * Eventgen "controller" API and responses
- * Eventgen "server" API and responses
- * Eventgen controller/server orchestration
- '''
-
- @classmethod
- def setup_class(cls):
- # Build the image from scratch
- cls.client = APIClient(base_url="unix://var/run/docker.sock")
- response = cls.client.build(path=REPO_DIR, dockerfile=os.path.join("dockerfiles", "Dockerfile"), tag=IMAGE_NAME, rm=True, nocache=True, pull=True, stream=False)
- for line in response:
- print line,
- # Create a network for both the controller + server to run in
- cls.client.create_network(NETWORK_NAME, driver="bridge", attachable=True)
- networking_config = cls.client.create_networking_config({NETWORK_NAME: cls.client.create_endpoint_config()})
- # Start the controller
- print 'creating controller'
- host_config = cls.client.create_host_config(auto_remove=True, publish_all_ports=True)
- container = cls.client.create_container(image=IMAGE_NAME,
- command="controller",
- host_config=host_config,
- networking_config=networking_config)
- cls.client.start(container["Id"])
- TestEventgenOrchestration.controller_id = container["Id"]
- print container["Id"]
- cls.controller_container = cls.client.inspect_container(container["Id"])
- cls.controller_eventgen_webport = cls.controller_container["NetworkSettings"]["Ports"]["9500/tcp"][0]["HostPort"]
- cls.controller_rabbitmq_webport = cls.controller_container["NetworkSettings"]["Ports"]["15672/tcp"][0]["HostPort"]
- # Start the server
- print 'creating server'
- container = cls.client.create_container(image=IMAGE_NAME,
- command="server",
- environment=["EVENTGEN_AMQP_HOST={}".format(cls.controller_container["Id"][:12])],
- host_config=host_config,
- networking_config=networking_config)
- cls.client.start(container["Id"])
- TestEventgenOrchestration.server_id = container["Id"]
- print container["Id"]
- cls.server_container = cls.client.inspect_container(container["Id"])
- cls.server_eventgen_webport = cls.server_container["NetworkSettings"]["Ports"]["9500/tcp"][0]["HostPort"]
- cls.server_rabbitmq_webport = cls.server_container["NetworkSettings"]["Ports"]["15672/tcp"][0]["HostPort"]
- # Wait for the controller to be available
- print "Waiting for Eventgen Controller to become available."
- wait_for_response("http://127.0.0.1:{}".format(cls.controller_eventgen_webport))
- print "Eventgen Controller has become available."
- # Wait for the server to be available
- print "Waiting for Eventgen Server to become available."
- wait_for_response("http://127.0.0.1:{}".format(cls.server_eventgen_webport))
- print "Eventgen Server has become available."
- time.sleep(60)
-
- @classmethod
- def teardown_class(cls):
- cls.client.remove_container(cls.server_container, v=True, force=True)
- cls.client.remove_container(cls.controller_container, v=True, force=True)
- cls.client.remove_image(IMAGE_NAME, force=True, noprune=False)
- cls.client.remove_network(NETWORK_NAME)
-
- ### Controller tests ###
-
- def test_controller_rabbitmq(self):
- r = requests.get("http://127.0.0.1:{}".format(self.controller_rabbitmq_webport))
- assert r.status_code == 200
- assert "RabbitMQ" in r.content
-
- def test_controller_root(self):
- r = requests.get("http://127.0.0.1:{}".format(self.controller_eventgen_webport))
- assert r.status_code == 200
- assert "Eventgen Controller" in r.content
- assert "Host: " in r.content
- assert "You are running Eventgen Controller" in r.content
-
- def test_controller_index(self):
- r = requests.get("http://127.0.0.1:{}/index".format(self.controller_eventgen_webport))
- assert r.status_code == 200
- assert "Eventgen Controller" in r.content
- assert "Host: " in r.content
- assert "You are running Eventgen Controller" in r.content
-
- def test_controller_status(self):
- max_retry = 5
- current_retry = 1
- output = {}
- while not output and current_retry <= max_retry:
- response = requests.get("http://127.0.0.1:{}/status".format(self.controller_eventgen_webport), timeout=10)
- if response.status_code == 200:
- output = json.loads(response.content)
- current_retry += 1
- time.sleep(10)
- assert output
-
- def test_controller_start(self):
- r = requests.post("http://127.0.0.1:{}/start".format(self.controller_eventgen_webport))
- assert r.status_code == 200
- assert "Start event dispatched to all" in r.content
-
- def test_controller_start_with_target(self):
- r = requests.post("http://127.0.0.1:{}/start/{}".format(self.controller_eventgen_webport, TestEventgenOrchestration.server_id[:12]))
- assert r.status_code == 200
- assert "Start event dispatched to {}".format(TestEventgenOrchestration.server_id[:12]) in r.content
-
- def test_controller_stop(self):
- r = requests.post("http://127.0.0.1:{}/stop".format(self.controller_eventgen_webport))
- assert r.status_code == 200
- assert "Stop event dispatched to all" in r.content
-
- def test_controller_stop_with_target(self):
- r = requests.post("http://127.0.0.1:{}/stop/{}".format(self.controller_eventgen_webport, TestEventgenOrchestration.server_id[:12]))
- assert r.status_code == 200
- assert "Stop event dispatched to {}".format(TestEventgenOrchestration.server_id[:12]) in r.content
-
- def test_controller_restart(self):
- r = requests.post("http://127.0.0.1:{}/stop".format(self.controller_eventgen_webport))
- assert r.status_code == 200
- assert "Stop event dispatched to all" in r.content
-
- def test_controller_restart_with_target(self):
- r = requests.post("http://127.0.0.1:{}/stop/{}".format(self.controller_eventgen_webport, TestEventgenOrchestration.server_id[:12]))
- assert r.status_code == 200
- assert "Stop event dispatched to {}".format(TestEventgenOrchestration.server_id[:12]) in r.content
-
- def test_controller_bundle_invalid_request(self):
- r = requests.post("http://127.0.0.1:{}/bundle".format(self.controller_eventgen_webport))
- assert r.status_code == 400
- assert "Please pass in a valid object with bundle URL" in r.content
-
- def test_controller_bundle_with_url(self):
- r = requests.post("http://127.0.0.1:{}/bundle".format(self.controller_eventgen_webport), json={"url": "http://server.com/bundle.tgz"})
- assert r.status_code == 200
- assert "Bundle event dispatched to all with url http://server.com/bundle.tgz" in r.content
-
- def test_controller_bundle_with_url_and_target(self):
- r = requests.post("http://127.0.0.1:{}/bundle/{}".format(self.controller_eventgen_webport, TestEventgenOrchestration.server_id[:12]), json={"url": "http://server.com/bundle.tgz"})
- assert r.status_code == 200
- assert "Bundle event dispatched to {} with url http://server.com/bundle.tgz".format(TestEventgenOrchestration.server_id[:12]) in r.content
-
- @pytest.mark.skip(reason="Change in implementation")
- def test_controller_get_volume(self):
- max_retry = 5
- current_retry = 1
- output = {}
- while not output and current_retry <= max_retry:
- response = requests.get("http://127.0.0.1:{}/volume".format(self.controller_eventgen_webport), timeout=10)
- if response.status_code == 200:
- output = json.loads(response.content)
- current_retry += 1
- time.sleep(10)
- assert output[TestEventgenOrchestration.server_id[:12]] == 0.0
-
- def test_controller_set_volume_invalid_request(self):
- r = requests.post("http://127.0.0.1:{}/volume".format(self.controller_eventgen_webport))
- assert r.status_code == 400
- assert "Please pass in a valid object with volume" in r.content
-
- def test_controller_set_volume_with_volume(self):
- r = requests.post("http://127.0.0.1:{}/volume".format(self.controller_eventgen_webport), json={"perDayVolume": 10})
- assert r.status_code == 200
- assert "set_volume event dispatched to all" in r.content
-
- def test_controller_set_volume_with_volume_and_target(self):
- r = requests.post("http://127.0.0.1:{}/volume/{}".format(self.controller_eventgen_webport, TestEventgenOrchestration.server_id[:12]), json={"perDayVolume": 10})
- assert r.status_code == 200
- assert "set_volume event dispatched to {}".format(TestEventgenOrchestration.server_id[:12]) in r.content
-
- ### Server tests ###
-
- def test_server_root(self):
- r = requests.get("http://127.0.0.1:{}".format(self.server_eventgen_webport))
- assert r.status_code == 200
- assert "Host: " in r.content
- assert "Eventgen Status" in r.content
- assert "Eventgen Config file path" in r.content
- assert "Total volume:" in r.content
- assert "Worker Queue Status" in r.content
- assert "Sample Queue Status" in r.content
- assert "Output Queue Status" in r.content
-
- def test_server_index(self):
- r = requests.get("http://127.0.0.1:{}/index".format(self.server_eventgen_webport))
- assert r.status_code == 200
- assert "Host: " in r.content
- assert "Eventgen Status" in r.content
- assert "Eventgen Config file path" in r.content
- assert "Total volume:" in r.content
- assert "Worker Queue Status" in r.content
- assert "Sample Queue Status" in r.content
- assert "Output Queue Status" in r.content
-
- def test_server_status(self):
- r = requests.get("http://127.0.0.1:{}/status".format(self.server_eventgen_webport))
- assert r.status_code == 200
- output = json.loads(r.content)
- assert output
- assert output['EVENTGEN_STATUS'] == 0
-
- def test_server_get_and_set_conf(self):
- r = requests.get("http://127.0.0.1:{}/conf".format(self.server_eventgen_webport))
- assert r.status_code == 200
- assert json.loads(r.content) == {}
- config_json = {"windbag": {"outputMode": "stdout"}}
- r = requests.post("http://127.0.0.1:{}/conf".format(self.server_eventgen_webport), json=config_json)
- assert r.status_code == 200
- assert json.loads(r.content) == config_json
-
- def test_server_start(self):
- r = requests.post("http://127.0.0.1:{}/start".format(self.server_eventgen_webport), timeout=5)
- assert r.status_code == 200
- assert json.loads(r.content) == "Eventgen has successfully started."
-
- def test_server_restart(self):
- r = requests.post("http://127.0.0.1:{}/restart".format(self.server_eventgen_webport))
- assert r.status_code == 200
- assert json.loads(r.content) == "Eventgen restarted."
-
- def test_server_stop(self):
- r = requests.post("http://127.0.0.1:{}/stop".format(self.server_eventgen_webport))
- assert r.status_code == 200
- assert json.loads(r.content) == "Eventgen is stopped."
-
- def test_server_bundle(self):
- r = requests.post("http://127.0.0.1:{}/bundle".format(self.server_eventgen_webport))
- assert r.status_code == 400
- assert "Please pass in a valid object with bundle URL" in r.content
-
- def test_server_get_and_set_volume(self):
- # Must initialize a stanza with the perDayVolume setting before hitting the /volume endpoint
- r = requests.put("http://127.0.0.1:{}/conf".format(self.server_eventgen_webport), json={"windbag": {}})
- assert r.status_code == 200
- assert json.loads(r.content)
- r = requests.post("http://127.0.0.1:{}/volume".format(self.server_eventgen_webport), json={"perDayVolume": 10})
- assert r.status_code == 200
- assert json.loads(r.content)
- r = requests.get("http://127.0.0.1:{}/volume".format(self.server_eventgen_webport))
- assert r.status_code == 200
- output = json.loads(r.content)
- assert output == 10.0
- r = requests.post("http://127.0.0.1:{}/volume".format(self.server_eventgen_webport), json={"perDayVolume": 150})
- assert r.status_code == 200
- assert json.loads(r.content)
- r = requests.get("http://127.0.0.1:{}/volume".format(self.server_eventgen_webport))
- assert r.status_code == 200
- output = json.loads(r.content)
- assert output == 150.0
+ """
+ This test class is used to test the Docker image published as part of this repo.
+ Specifically, this is testing:
+ * Eventgen "controller" API and responses
+ * Eventgen "server" API and responses
+ * Eventgen controller/server orchestration
+ """
+
+ @classmethod
+ def setup_class(cls):
+ # Build the image from scratch
+ cls.client = APIClient(base_url="unix://var/run/docker.sock")
+ response = cls.client.build(path=REPO_DIR, dockerfile=os.path.join("dockerfiles", "Dockerfile"), tag=IMAGE_NAME,
+ rm=True, nocache=True, pull=True, stream=False)
+ for line in response:
+ print line,
+ # Create a network for both the controller + server to run in
+ cls.client.create_network(NETWORK_NAME, driver="bridge", attachable=True)
+ networking_config = cls.client.create_networking_config({NETWORK_NAME: cls.client.create_endpoint_config()})
+ # Start the controller
+ print 'creating controller'
+ host_config = cls.client.create_host_config(auto_remove=True, publish_all_ports=True)
+ container = cls.client.create_container(image=IMAGE_NAME, command="controller", host_config=host_config,
+ networking_config=networking_config)
+ cls.client.start(container["Id"])
+ TestEventgenOrchestration.controller_id = container["Id"]
+ print container["Id"]
+ cls.controller_container = cls.client.inspect_container(container["Id"])
+ cls.controller_eventgen_webport = cls.controller_container["NetworkSettings"]["Ports"]["9500/tcp"][0][
+ "HostPort"]
+ cls.controller_rabbitmq_webport = cls.controller_container["NetworkSettings"]["Ports"]["15672/tcp"][0][
+ "HostPort"]
+ # Start the server
+ print 'creating server'
+ container = cls.client.create_container(
+ image=IMAGE_NAME, command="server", environment=[
+ "EVENTGEN_AMQP_HOST={}".format(cls.controller_container["Id"][:12])], host_config=host_config,
+ networking_config=networking_config)
+ cls.client.start(container["Id"])
+ TestEventgenOrchestration.server_id = container["Id"]
+ print container["Id"]
+ cls.server_container = cls.client.inspect_container(container["Id"])
+ cls.server_eventgen_webport = cls.server_container["NetworkSettings"]["Ports"]["9500/tcp"][0]["HostPort"]
+ cls.server_rabbitmq_webport = cls.server_container["NetworkSettings"]["Ports"]["15672/tcp"][0]["HostPort"]
+ # Wait for the controller to be available
+ print "Waiting for Eventgen Controller to become available."
+ wait_for_response("http://127.0.0.1:{}".format(cls.controller_eventgen_webport))
+ print "Eventgen Controller has become available."
+ # Wait for the server to be available
+ print "Waiting for Eventgen Server to become available."
+ wait_for_response("http://127.0.0.1:{}".format(cls.server_eventgen_webport))
+ print "Eventgen Server has become available."
+ time.sleep(60)
+
+ @classmethod
+ def teardown_class(cls):
+ cls.client.remove_container(cls.server_container, v=True, force=True)
+ cls.client.remove_container(cls.controller_container, v=True, force=True)
+ cls.client.remove_image(IMAGE_NAME, force=True, noprune=False)
+ cls.client.remove_network(NETWORK_NAME)
+
+ # Controller tests #
+
+ def test_controller_rabbitmq(self):
+ r = requests.get("http://127.0.0.1:{}".format(self.controller_rabbitmq_webport))
+ assert r.status_code == 200
+ assert "RabbitMQ" in r.content
+
+ def test_controller_root(self):
+ r = requests.get("http://127.0.0.1:{}".format(self.controller_eventgen_webport))
+ assert r.status_code == 200
+ assert "Eventgen Controller" in r.content
+ assert "Host: " in r.content
+ assert "You are running Eventgen Controller" in r.content
+
+ def test_controller_index(self):
+ r = requests.get("http://127.0.0.1:{}/index".format(self.controller_eventgen_webport))
+ assert r.status_code == 200
+ assert "Eventgen Controller" in r.content
+ assert "Host: " in r.content
+ assert "You are running Eventgen Controller" in r.content
+
+ def test_controller_status(self):
+ max_retry = 5
+ current_retry = 1
+ output = {}
+ while not output and current_retry <= max_retry:
+ response = requests.get("http://127.0.0.1:{}/status".format(self.controller_eventgen_webport), timeout=10)
+ if response.status_code == 200:
+ output = json.loads(response.content)
+ current_retry += 1
+ time.sleep(10)
+ assert output
+
+ def test_controller_start(self):
+ r = requests.post("http://127.0.0.1:{}/start".format(self.controller_eventgen_webport))
+ assert r.status_code == 200
+ assert "Start event dispatched to all" in r.content
+
+ def test_controller_start_with_target(self):
+ r = requests.post("http://127.0.0.1:{}/start/{}".format(self.controller_eventgen_webport,
+ TestEventgenOrchestration.server_id[:12]))
+ assert r.status_code == 200
+ assert "Start event dispatched to {}".format(TestEventgenOrchestration.server_id[:12]) in r.content
+
+ def test_controller_stop(self):
+ r = requests.post("http://127.0.0.1:{}/stop".format(self.controller_eventgen_webport))
+ assert r.status_code == 200
+ assert "Stop event dispatched to all" in r.content
+
+ def test_controller_stop_with_target(self):
+ r = requests.post("http://127.0.0.1:{}/stop/{}".format(self.controller_eventgen_webport,
+ TestEventgenOrchestration.server_id[:12]))
+ assert r.status_code == 200
+ assert "Stop event dispatched to {}".format(TestEventgenOrchestration.server_id[:12]) in r.content
+
+ def test_controller_restart(self):
+ r = requests.post("http://127.0.0.1:{}/stop".format(self.controller_eventgen_webport))
+ assert r.status_code == 200
+ assert "Stop event dispatched to all" in r.content
+
+ def test_controller_restart_with_target(self):
+ r = requests.post("http://127.0.0.1:{}/stop/{}".format(self.controller_eventgen_webport,
+ TestEventgenOrchestration.server_id[:12]))
+ assert r.status_code == 200
+ assert "Stop event dispatched to {}".format(TestEventgenOrchestration.server_id[:12]) in r.content
+
+ def test_controller_bundle_invalid_request(self):
+ r = requests.post("http://127.0.0.1:{}/bundle".format(self.controller_eventgen_webport))
+ assert r.status_code == 400
+ assert "Please pass in a valid object with bundle URL" in r.content
+
+ def test_controller_bundle_with_url(self):
+ r = requests.post("http://127.0.0.1:{}/bundle".format(self.controller_eventgen_webport), json={
+ "url": "http://server.com/bundle.tgz"})
+ assert r.status_code == 200
+ assert "Bundle event dispatched to all with url http://server.com/bundle.tgz" in r.content
+
+ def test_controller_bundle_with_url_and_target(self):
+ r = requests.post(
+ "http://127.0.0.1:{}/bundle/{}".format(self.controller_eventgen_webport,
+ TestEventgenOrchestration.server_id[:12]), json={
+ "url": "http://server.com/bundle.tgz"})
+ assert r.status_code == 200
+ assert "Bundle event dispatched to {} with url http://server.com/bundle.tgz".format(
+ TestEventgenOrchestration.server_id[:12]) in r.content
+
+ @pytest.mark.skip(reason="Change in implementation")
+ def test_controller_get_volume(self):
+ max_retry = 5
+ current_retry = 1
+ output = {}
+ while not output and current_retry <= max_retry:
+ response = requests.get("http://127.0.0.1:{}/volume".format(self.controller_eventgen_webport), timeout=10)
+ if response.status_code == 200:
+ output = json.loads(response.content)
+ current_retry += 1
+ time.sleep(10)
+ assert output[TestEventgenOrchestration.server_id[:12]] == 0.0
+
+ def test_controller_set_volume_invalid_request(self):
+ r = requests.post("http://127.0.0.1:{}/volume".format(self.controller_eventgen_webport))
+ assert r.status_code == 400
+ assert "Please pass in a valid object with volume" in r.content
+
+ def test_controller_set_volume_with_volume(self):
+ r = requests.post("http://127.0.0.1:{}/volume".format(self.controller_eventgen_webport), json={
+ "perDayVolume": 10})
+ assert r.status_code == 200
+ assert "set_volume event dispatched to all" in r.content
+
+ def test_controller_set_volume_with_volume_and_target(self):
+ r = requests.post(
+ "http://127.0.0.1:{}/volume/{}".format(self.controller_eventgen_webport,
+ TestEventgenOrchestration.server_id[:12]), json={"perDayVolume": 10})
+ assert r.status_code == 200
+ assert "set_volume event dispatched to {}".format(TestEventgenOrchestration.server_id[:12]) in r.content
+
+ # Server tests #
+
+ def test_server_root(self):
+ r = requests.get("http://127.0.0.1:{}".format(self.server_eventgen_webport))
+ assert r.status_code == 200
+ assert "Host: " in r.content
+ assert "Eventgen Status" in r.content
+ assert "Eventgen Config file path" in r.content
+ assert "Total volume:" in r.content
+ assert "Worker Queue Status" in r.content
+ assert "Sample Queue Status" in r.content
+ assert "Output Queue Status" in r.content
+
+ def test_server_index(self):
+ r = requests.get("http://127.0.0.1:{}/index".format(self.server_eventgen_webport))
+ assert r.status_code == 200
+ assert "Host: " in r.content
+ assert "Eventgen Status" in r.content
+ assert "Eventgen Config file path" in r.content
+ assert "Total volume:" in r.content
+ assert "Worker Queue Status" in r.content
+ assert "Sample Queue Status" in r.content
+ assert "Output Queue Status" in r.content
+
+ def test_server_status(self):
+ r = requests.get("http://127.0.0.1:{}/status".format(self.server_eventgen_webport))
+ assert r.status_code == 200
+ output = json.loads(r.content)
+ assert output
+ assert output['EVENTGEN_STATUS'] == 0
+
+ def test_server_get_and_set_conf(self):
+ r = requests.get("http://127.0.0.1:{}/conf".format(self.server_eventgen_webport))
+ assert r.status_code == 200
+ assert json.loads(r.content) == {}
+ config_json = {"windbag": {"outputMode": "stdout"}}
+ r = requests.post("http://127.0.0.1:{}/conf".format(self.server_eventgen_webport), json=config_json)
+ assert r.status_code == 200
+ assert json.loads(r.content) == config_json
+
+ def test_server_start(self):
+ r = requests.post("http://127.0.0.1:{}/start".format(self.server_eventgen_webport), timeout=5)
+ assert r.status_code == 200
+ assert json.loads(r.content) == "Eventgen has successfully started."
+
+ def test_server_restart(self):
+ r = requests.post("http://127.0.0.1:{}/restart".format(self.server_eventgen_webport))
+ assert r.status_code == 200
+ assert json.loads(r.content) == "Eventgen restarted."
+
+ def test_server_stop(self):
+ r = requests.post("http://127.0.0.1:{}/stop".format(self.server_eventgen_webport))
+ assert r.status_code == 200
+ assert json.loads(r.content) == "Eventgen is stopped."
+
+ def test_server_bundle(self):
+ r = requests.post("http://127.0.0.1:{}/bundle".format(self.server_eventgen_webport))
+ assert r.status_code == 400
+ assert "Please pass in a valid object with bundle URL" in r.content
+
+ def test_server_get_and_set_volume(self):
+ # Must initialize a stanza with the perDayVolume setting before hitting the /volume endpoint
+ r = requests.put("http://127.0.0.1:{}/conf".format(self.server_eventgen_webport), json={"windbag": {}})
+ assert r.status_code == 200
+ assert json.loads(r.content)
+ r = requests.post("http://127.0.0.1:{}/volume".format(self.server_eventgen_webport), json={"perDayVolume": 10})
+ assert r.status_code == 200
+ assert json.loads(r.content)
+ r = requests.get("http://127.0.0.1:{}/volume".format(self.server_eventgen_webport))
+ assert r.status_code == 200
+ output = json.loads(r.content)
+ assert output == 10.0
+ r = requests.post("http://127.0.0.1:{}/volume".format(self.server_eventgen_webport), json={"perDayVolume": 150})
+ assert r.status_code == 200
+ assert json.loads(r.content)
+ r = requests.get("http://127.0.0.1:{}/volume".format(self.server_eventgen_webport))
+ assert r.status_code == 200
+ output = json.loads(r.content)
+ assert output == 150.0
diff --git a/tests/large/test_mode_replay.py b/tests/large/test_mode_replay.py
new file mode 100644
index 00000000..b58c8f51
--- /dev/null
+++ b/tests/large/test_mode_replay.py
@@ -0,0 +1,61 @@
+from datetime import datetime
+import re
+import time
+import pytest
+
+
+def test_mode_replay(eventgen_test_helper):
+ """Test normal replay mode settings"""
+ events = eventgen_test_helper('eventgen_replay.conf').get_events()
+ # assert the event length is the same as sample file size
+ assert len(events) == 12
+ pattern = re.compile(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}")
+ for event in events:
+ # assert that integer token is replaced
+ assert "@@integer" not in event
+ result = pattern.match(event)
+ assert result is not None
+
+
+def test_mode_replay_end_1(eventgen_test_helper):
+ """Test normal replay mode with end = 2 which will replay the sample twice and exit"""
+ events = eventgen_test_helper('eventgen_replay_end_1.conf').get_events()
+ # assert the event length is twice of the events in the sample file
+ assert len(events) == 24
+
+
+def test_mode_replay_end_2(eventgen_test_helper):
+ """Test normal replay mode with end = -1 which will replay the sample forever"""
+ helper = eventgen_test_helper('eventgen_replay_end_2.conf')
+ time.sleep(60)
+ assert helper.is_alive()
+
+
+def test_mode_replay_backfill(eventgen_test_helper):
+ """Test normal replay mode with backfill = -5s which should be ignore since backfill < interval"""
+ events = eventgen_test_helper('eventgen_replay_backfill.conf').get_events()
+ # assert the events length is twice of the events in the sample file
+ assert len(events) == 24
+
+
+@pytest.mark.skip(reason="this issue is not fixed")
+def test_mode_replay_timemultiple(eventgen_test_helper):
+ """Test normal replay mode with timeMultiple = 0.5 which will replay the sample with half time interval"""
+ current_datetime = datetime.now()
+ events = eventgen_test_helper('eventgen_replay_timeMultiple.conf').get_events()
+
+ pattern = re.compile(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}")
+ for event in events:
+ result = pattern.match(event)
+ assert result is not None
+ event_datetime = datetime.strptime(result.group(), "%Y-%m-%d %H:%M:%S")
+ delter_seconds = (event_datetime - current_datetime).total_seconds()
+ # assert the event time is after (now - earliest) time
+ assert delter_seconds < 11
+
+
+def test_mode_replay_csv(eventgen_test_helper):
+ """Test normal replay mode with sampletype = csv which will get _raw row from the sample"""
+ events = eventgen_test_helper('eventgen_replay_csv.conf').get_events()
+ # assert the events equals to the sample csv file
+ assert len(events) == 10
diff --git a/tests/large/test_mode_sample.py b/tests/large/test_mode_sample.py
new file mode 100644
index 00000000..e7d1575f
--- /dev/null
+++ b/tests/large/test_mode_sample.py
@@ -0,0 +1,101 @@
+from datetime import datetime
+import re
+
+
+def test_mode_sample(eventgen_test_helper):
+ """Test normal sample mode with sampletype = raw"""
+ current_datetime = datetime.now()
+ events = eventgen_test_helper("eventgen_sample.conf").get_events()
+ # assert the event length is the same as sample file size when end = 1
+ assert len(events) == 12
+ pattern = re.compile(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}")
+ for event in events:
+ # assert that integer token is replaced
+ assert "@@integer" not in event
+ result = pattern.match(event)
+ assert result is not None
+ event_datetime = datetime.strptime(result.group(), "%Y-%m-%d %H:%M:%S")
+ delter_seconds = (event_datetime - current_datetime).total_seconds()
+ # assert the event time is after (now - earliest) time
+ assert delter_seconds > -20
+
+
+def test_mode_sample_csv(eventgen_test_helper):
+ """Test normal sample mode with sampletype = csv"""
+ events = eventgen_test_helper("eventgen_sample_csv.conf").get_events()
+ # assert the event length is the same as sample file size when end = 1
+ assert len(events) == 10
+
+
+def test_mode_sample_interval(eventgen_test_helper):
+ """Test normal sample mode with interval = 10s"""
+ events = eventgen_test_helper("eventgen_sample_interval.conf", timeout=30).get_events()
+ # assert the total events count is 12 * 3
+ assert len(events) == 36
+
+
+def test_mode_sample_end(eventgen_test_helper):
+ """Test normal sample mode with end = 1 and outputMode = file which will generate from the sample once"""
+ helper = eventgen_test_helper("eventgen_sample_end.conf")
+ events = helper.get_events()
+ # assert the event length is the same as sample file size when end = 1
+ assert len(events) == 12
+
+
+def test_mode_sample_backfill(eventgen_test_helper):
+ """Test normal sample mode with end = 1 and backfill = -15s which will generate from the sample once"""
+ current_datetime = datetime.now()
+ helper = eventgen_test_helper("eventgen_sample_backfill.conf")
+ events = helper.get_events()
+ pattern = re.compile(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}")
+ for event in events:
+ result = pattern.match(event)
+ assert result is not None
+ event_datetime = datetime.strptime(result.group(), "%Y-%m-%d %H:%M:%S")
+ delter_seconds = (event_datetime - current_datetime).total_seconds()
+ # assert the event time is after (now - backfill) time
+ assert delter_seconds > -15
+
+
+def test_mode_sample_breaker(eventgen_test_helper):
+ r"""Test sample mode with end = 1, count = 3 and breaker = ^\d{14}\.\d{6}"""
+ helper = eventgen_test_helper("eventgen_sample_breaker.conf")
+ events = helper.get_events()
+ assert len(events) == 3
+
+
+def test_mode_sample_earliest(eventgen_test_helper):
+ """Test sample mode with earliest = -15s"""
+ current_datetime = datetime.now()
+ helper = eventgen_test_helper("eventgen_sample_earliest.conf")
+ events = helper.get_events()
+ pattern = re.compile(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}")
+ for event in events:
+ result = pattern.match(event)
+ assert result is not None
+ event_datetime = datetime.strptime(result.group(), "%Y-%m-%d %H:%M:%S")
+ delter_seconds = (event_datetime - current_datetime).total_seconds()
+ # assert the event time is after (now - earliest) + 1 time, plus 1 to make it less flaky
+ assert delter_seconds > -16
+
+
+def test_mode_sample_latest(eventgen_test_helper):
+ """Test sample mode with latest = +15s"""
+ current_datetime = datetime.now()
+ helper = eventgen_test_helper("eventgen_sample_latest.conf")
+ events = helper.get_events()
+ pattern = re.compile(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}")
+ for event in events:
+ result = pattern.match(event)
+ assert result is not None
+ event_datetime = datetime.strptime(result.group(), "%Y-%m-%d %H:%M:%S")
+ delter_seconds = (event_datetime - current_datetime).total_seconds()
+ # assert the event time is after (now - earliest) time
+ assert delter_seconds < 16
+
+
+def test_mode_sample_count(eventgen_test_helper):
+ """Test sample mode with count = 5 which will output 5 events"""
+ helper = eventgen_test_helper("eventgen_sample_count.conf")
+ events = helper.get_events()
+ assert len(events) == 5
diff --git a/tests/large/test_token_replacement.py b/tests/large/test_token_replacement.py
new file mode 100644
index 00000000..c602c291
--- /dev/null
+++ b/tests/large/test_token_replacement.py
@@ -0,0 +1,68 @@
+import json
+import os
+import csv
+import re
+
+base_dir = os.path.dirname(os.path.abspath(__file__))
+
+
+def test_token_replacement(eventgen_test_helper):
+ """Test token replcement with replacementType= static | random | file | timestamp"""
+ events = eventgen_test_helper("eventgen_token_replacement.conf").get_events()
+ # assert the events size is 10 since end = 1
+ assert len(events) == 10
+
+ with open(os.path.join(base_dir, 'sample', 'id.csv'), 'rb') as f:
+ id_content = f.read()
+ with open(os.path.join(base_dir, 'sample', 'ip.csv'), 'rb') as f:
+ ip_content = f.read()
+ with open(os.path.join(base_dir, 'sample', 'cp.csv'), 'rb') as f:
+ cp_content = f.read()
+ with open(os.path.join(base_dir, 'sample', 'city.csv'), 'rb') as f:
+ reader = csv.reader(f)
+ country = []
+ city = []
+ latitude = []
+ longitude = []
+ for row in reader:
+ country.append(row[0])
+ city.append(row[1])
+ latitude.append(row[3])
+ longitude.append(row[4])
+
+ integer_id_seed = 1
+ for event in events:
+ try:
+ event_obj = json.loads(event)
+ except ValueError:
+ raise Exception("Token replacement error")
+
+ # assert replacementType = integerid
+ assert int(event_obj["ppcustomdata"]["receiver_id"]) == integer_id_seed
+ integer_id_seed += 1
+
+ # assert replacementType = file
+ assert event_obj["id"] in id_content
+ assert event_obj["cp"] in cp_content
+ assert event_obj["message"]["cliIP"] in ip_content
+
+ # assert replacementType = static
+ assert event_obj["netPerf"]["lastByte"] == "0"
+
+ # assert replacementType = random and replacement = integer[:]
+ assert 5000 > int(event_obj["message"]["bytes"]) > 40
+
+ # assert replacementType = random and replacement = ipv4 | ipv6 | mac
+ ipv4_pattern = re.compile(r"^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$")
+ ipv6_pattern = re.compile(r"^([A-Fa-f0-9]{1,4}:){7}[A-Fa-f0-9]{1,4}$")
+ mac_pattern = re.compile(r"^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$")
+
+ assert ipv4_pattern.match(event_obj["akadebug"]["Ak_IP"]) is not None
+ assert ipv6_pattern.match(event_obj["akadebug"]["forward-origin-ip"]) is not None
+ assert mac_pattern.match(event_obj["akadebug"]["end-user-ip"]) is not None
+
+ # assert replacementType = file | mvfile and replacement = :
+ assert event_obj["geo"]["city"] in city
+ assert event_obj["geo"]["country"] in country
+ assert event_obj["geo"]["lat"] in latitude
+ assert event_obj["geo"]["long"] in longitude
diff --git a/tests/large/utils/__init__.py b/tests/large/utils/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/large/utils/eventgen_test_helper.py b/tests/large/utils/eventgen_test_helper.py
new file mode 100644
index 00000000..c53a04e6
--- /dev/null
+++ b/tests/large/utils/eventgen_test_helper.py
@@ -0,0 +1,77 @@
+import os
+import subprocess
+import re
+from threading import Timer
+
+import configparser
+
+# $EVENTGEN_HOME/tests/large
+base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+# change working directory so that 'splunk_eventgen' call in the project root directory
+os.chdir(os.path.dirname(os.path.dirname(base_dir)))
+
+
+class EventgenTestHelper(object):
+ def __init__(self, conf, timeout=None):
+ self.conf = os.path.join(base_dir, 'conf', conf)
+ self.config, self.section = self._read_conf(self.conf)
+ self.output_mode = self._get_output_mode()
+ self.file_name = self._get_file_name()
+ self.breaker = self._get_breaker()
+ self.process = subprocess.Popen(['splunk_eventgen', 'generate', self.conf], stdout=subprocess.PIPE)
+ if timeout:
+ timer = Timer(timeout, self.kill)
+ timer.start()
+
+ def kill(self):
+ self.process.kill()
+
+ def is_alive(self):
+ if self.process.poll() is None:
+ return True
+ else:
+ return False
+
+ def get_events(self):
+ """Get events either from stdout or from file"""
+ self.process.wait()
+ if self.output_mode == 'stdout':
+ output = self.process.communicate()[0]
+ elif self.output_mode == 'file':
+ with open(os.path.join(base_dir, 'results', self.file_name), 'r') as f:
+ output = f.read()
+
+ if self.breaker[0] == '^':
+ self.breaker = self.breaker[1:]
+ if self.breaker[-1] == '$':
+ self.breaker = self.breaker[:-1]
+ results = re.split(self.breaker, output)
+ return [x for x in results if x != ""]
+
+ def tear_down(self):
+ """Kill sub-processes and remove results file"""
+ if self.is_alive():
+ self.process.kill()
+ if self.file_name:
+ os.remove(os.path.join(base_dir, 'results', self.file_name))
+
+ def _get_output_mode(self):
+ return self.config.get(self.section, 'outputMode', fallback=None)
+
+ def _get_file_name(self):
+ file_name = None
+ file_name_value = self.config.get(self.section, 'fileName', fallback=None)
+ if file_name_value is not None:
+ file_name = file_name_value.split(os.sep)[-1]
+ return file_name
+
+ def _get_breaker(self):
+ return self.config.get(self.section, 'breaker', fallback='\n')
+
+ @staticmethod
+ def _read_conf(conf):
+ config = configparser.ConfigParser()
+ config.read(conf)
+ if len(config.sections()) != 1 or config.sections()[0] == 'default' or config.sections()[0] == 'global':
+ raise Exception("Invalid test eventgen conf")
+ return config, config.sections()[0]
diff --git a/tests/medium/plugins/test_file_output.py b/tests/medium/plugins/test_file_output.py
index d1b7a92a..f290f640 100644
--- a/tests/medium/plugins/test_file_output.py
+++ b/tests/medium/plugins/test_file_output.py
@@ -3,7 +3,9 @@
import os
import sys
+
from mock import patch
+
from splunk_eventgen.__main__ import parse_args
from splunk_eventgen.eventgen_core import EventGenerator
@@ -11,7 +13,6 @@
class TestFileOutputPlugin(object):
-
def test_output_data_to_file(self):
configfile = "tests/sample_eventgen_conf/medium_test/eventgen.conf.fileoutput"
testargs = ["eventgen", "generate", configfile]
diff --git a/tests/medium/plugins/test_jinja_generator.py b/tests/medium/plugins/test_jinja_generator.py
index beab0b82..0bb7bd96 100644
--- a/tests/medium/plugins/test_jinja_generator.py
+++ b/tests/medium/plugins/test_jinja_generator.py
@@ -1,5 +1,6 @@
import os
import sys
+
from mock import patch
from splunk_eventgen.__main__ import parse_args
from splunk_eventgen.eventgen_core import EventGenerator
@@ -9,7 +10,7 @@
class TestJinjaGenerator(object):
-
+
def test_jinja_generator_to_file(self):
configfile = "tests/sample_eventgen_conf/jinja/eventgen.conf.jinja_basic"
testargs = ["eventgen", "generate", configfile]
diff --git a/tests/medium/plugins/test_syslog_output.py b/tests/medium/plugins/test_syslog_output.py
index eb5b8c45..831296c4 100644
--- a/tests/medium/plugins/test_syslog_output.py
+++ b/tests/medium/plugins/test_syslog_output.py
@@ -3,7 +3,9 @@
import os
import sys
+
from mock import MagicMock, patch
+
from splunk_eventgen.__main__ import parse_args
from splunk_eventgen.eventgen_core import EventGenerator
from splunk_eventgen.lib.plugins.output.syslogout import SyslogOutOutputPlugin
@@ -12,12 +14,11 @@
class TestSyslogOutputPlugin(object):
-
def test_output_data_to_syslog(self):
configfile = "tests/sample_eventgen_conf/medium_test/eventgen.conf.syslogoutput"
testargs = ["eventgen", "generate", configfile]
with patch.object(sys, 'argv', testargs):
- with patch('logging.getLogger') as mock_log:
+ with patch('logging.getLogger'):
pargs = parse_args()
assert pargs.subcommand == 'generate'
assert pargs.configfile == configfile
diff --git a/tests/medium/plugins/test_tcp_output.py b/tests/medium/plugins/test_tcp_output.py
index e62ecdaa..e3ea1320 100644
--- a/tests/medium/plugins/test_tcp_output.py
+++ b/tests/medium/plugins/test_tcp_output.py
@@ -3,7 +3,9 @@
import os
import sys
+
from mock import MagicMock, patch
+
from splunk_eventgen.__main__ import parse_args
from splunk_eventgen.eventgen_core import EventGenerator
from splunk_eventgen.lib.plugins.output.tcpout import TcpOutputPlugin
@@ -12,7 +14,6 @@
class TestTcpOutputPlugin(object):
-
def test_output_data_to_tcp_port(self):
configfile = "tests/sample_eventgen_conf/medium_test/eventgen.conf.tcpoutput"
testargs = ["eventgen", "generate", configfile]
@@ -35,4 +36,3 @@ def test_output_data_to_tcp_port(self):
eventgen.start()
tcpoutput.s.connect.assert_called_with(('127.0.0.1', 9999))
assert tcpoutput.s.send.call_count == 5
-
diff --git a/tests/medium/plugins/test_udp_output.py b/tests/medium/plugins/test_udp_output.py
index aec78fa6..a7cbde26 100644
--- a/tests/medium/plugins/test_udp_output.py
+++ b/tests/medium/plugins/test_udp_output.py
@@ -3,7 +3,9 @@
import os
import sys
+
from mock import MagicMock, patch
+
from splunk_eventgen.__main__ import parse_args
from splunk_eventgen.eventgen_core import EventGenerator
from splunk_eventgen.lib.plugins.output.udpout import UdpOutputPlugin
@@ -12,7 +14,6 @@
class TestUdpOutputPlugin(object):
-
def test_output_data_to_udp_port(self):
configfile = "tests/sample_eventgen_conf/medium_test/eventgen.conf.udpoutput"
testargs = ["eventgen", "generate", configfile]
diff --git a/tests/run_tests.py b/tests/run_tests.py
index 871c29c2..8d433456 100644
--- a/tests/run_tests.py
+++ b/tests/run_tests.py
@@ -1,7 +1,8 @@
-import pytest
-import sys
-import time
import os
+import sys
+
+import pytest
+
SMALL = 'tests/small'
MEDIUM = 'tests/medium'
LARGE = 'tests/large'
@@ -11,13 +12,12 @@
ENV = os.environ
PATH = sys.path
-# Set to 1 is debugging is a problem. Normally, it is 8, which should match the cores/hyperthreads of most of our systems.
+# Normally, it is 8, which should match the cores/hyperthreads of most of our systems.
NUM_TEST_WORKERS_LARGE = '8'
-
"""
How to run the tests:
1. python run_tests.py
-2. python run_tests.py {SMALL_TESTS_TO_RUN} {MEDIUM_TESTS_TO_RUN} {LARGE_TESTS_TO_RUN} {XLARGE_TESTS_TO_RUN} {optional RUN_DESTROY}
+2. python run_tests.py {SMALL_TEST_PATH} {MEDIUM_TEST_PATH} {LARGE_TEST_PATH} {XLARGE_TEST_PATH} {optional RUN_DESTROY}
- You can pass 'None' as a value to either to ignore those tests
- To run a specific folder, file, pass it in as a value. ex
* python run_tests.py None None tests/large/test_destroy.py None
@@ -46,7 +46,9 @@
if SMALL:
sys.path = PATH
os.environ = ENV
- args = [ "--cov=splunk_eventgen", "--cov-config=tests/.coveragerc", "--cov-report=term", "--cov-report=html", SMALL, "--junitxml=tests/test-reports/tests_small_results.xml"]
+ args = [
+ "--cov=splunk_eventgen", "--cov-config=tests/.coveragerc", "--cov-report=term", "--cov-report=html", SMALL,
+ "--junitxml=tests/test-reports/tests_small_results.xml"]
return_codes.append(pytest.main(args))
# Run medium tests
diff --git a/tests/sample_eventgen_conf/unit/eventgen.conf.config b/tests/sample_eventgen_conf/unit/eventgen.conf.config
new file mode 100644
index 00000000..81f3c44e
--- /dev/null
+++ b/tests/sample_eventgen_conf/unit/eventgen.conf.config
@@ -0,0 +1,38 @@
+[sample]
+sampleDir = tests/sample_eventgen_conf/sample
+outputMode = splunkstream
+splunkMethod = https
+splunkHost = localhost
+splunkPort = 8088
+earliest = -3s
+latest = now
+
+count = -1
+delay = 10
+interval = 3
+
+perDayVolume = 1
+randomizeCount = 0.2
+timeMultiple = 2
+
+disabled = false
+profiler = false
+useOutputQueue = false
+bundlelines = false
+httpeventWaitResponse = false
+sequentialTimestamp = false
+autotimestamp = false
+randomizeEvents = false
+outputCounter = false
+
+minuteOfHourRate = { "0": 1, "1": 1, "2": 1, "3": 1, "4": 1, "5": 1, "6": 1, "7": 1, "8": 1, "9": 1, "10": 1, "11": 1, "12": 1, "13": 1, "14": 1, "15": 1, "16": 1, "17": 1, "18": 1, "19": 1, "20": 1, "21": 1, "22": 1, "23": 1, "24": 1, "25": 1, "26": 1, "27": 1, "28": 1, "29": 1, "30": 1, "31": 1, "32": 1, "33": 1, "34": 1, "35": 4, "36": 0.1, "37": 0.1, "38": 1, "39": 1, "40": 1, "41": 1, "42": 1, "43": 1, "44": 1, "45": 1, "46": 1, "47": 1, "48": 1, "49": 1, "50": 1, "51": 1, "52": 1, "53": 1, "54": 1, "55": 1, "56": 1, "57": 1, "58": 1, "59": 1 }
+hourOfDayRate = { "0": 0.30, "1": 0.20, "2": 0.20, "3": 0.20, "4": 0.20, "5": 0.25, "6": 0.35, "7": 0.50, "8": 0.60, "9": 0.65, "10": 0.70, "11": 0.75, "12": 0.77, "13": 0.80, "14": 0.82, "15": 0.85, "16": 0.87, "17": 0.90, "18": 0.95, "19": 1.0, "20": 0.85, "21": 0.70, "22": 0.60, "23": 0.45 }
+dayOfWeekRate = { "0": 0.97, "1": 0.95, "2": 0.90, "3": 0.97, "4": 1.0, "5": 0.99, "6": 0.55 }
+dayOfMonthRate = { "1": 1, "2": 1, "3": 1, "4": 1, "5": 1, "6": 1, "7": 1, "8": 1, "9": 1, "10": 1, "11": 1, "12": 1, "13": 1, "14": 1, "15": 1, "16": 1, "17": 1, "18": 1, "19": 1, "20": 1, "21": 1, "22": 1, "23": 1, "24": 1, "25": 1, "26": 1, "27": 1, "28": 1, "29": 1, "30": 1, "31": 1 }
+monthOfYearRate = { "1": 1, "2": 1, "3": 1, "4": 1, "5": 1, "6": 1, "7": 1, "8": 1, "9": 1, "10": 1, "11": 1, "12": 1 }
+httpeventServers = {"servers":[{ "protocol":"https", "address":"127.0.0.1", "port":"8088", "key":"8d5ab52c-3759-49e3-b66a-5213ce525692"}]}
+autotimestamps = [["\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}", "%Y-%m-%d %H:%M:%S"], ["\\d{1,2}\\/\\w{3}\\/\\d{4}\\s\\d{2}:\\d{2}:\\d{2}:\\d{1,3}", "%d/%b/%Y %H:%M:%S:%f"], ["\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}", "%Y-%m-%dT%H:%M:%S.%f"], ["\\d{1,2}/\\w{3}/\\d{4}\\s\\d{2}:\\d{2}:\\d{2}:\\d{1,3}", "%d/%b/%Y %H:%M:%S:%f"], ["\\d{1,2}/\\d{2}/\\d{2}\\s\\d{1,2}:\\d{2}:\\d{2}", "%m/%d/%y %H:%M:%S"], ["\\d{2}-\\d{2}-\\d{4} \\d{2}:\\d{2}:\\d{2}", "%m-%d-%Y %H:%M:%S"], ["\\w{3} \\w{3} +\\d{1,2} \\d{2}:\\d{2}:\\d{2}", "%a %b %d %H:%M:%S"], ["\\w{3} \\w{3} \\d{2} \\d{4} \\d{2}:\\d{2}:\\d{2}", "%a %b %d %Y %H:%M:%S"], ["^(\\w{3}\\s+\\d{1,2}\\s\\d{2}:\\d{2}:\\d{2})", "%b %d %H:%M:%S"], ["(\\w{3}\\s+\\d{1,2}\\s\\d{1,2}:\\d{1,2}:\\d{1,2})", "%b %d %H:%M:%S"], ["(\\w{3}\\s\\d{1,2}\\s\\d{1,4}\\s\\d{1,2}:\\d{1,2}:\\d{1,2})", "%b %d %Y %H:%M:%S"], ["\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3}", "%Y-%m-%d %H:%M:%S.%f"], ["\\,\\d{2}\\/\\d{2}\\/\\d{2,4}\\s+\\d{2}:\\d{2}:\\d{2}\\s+[AaPp][Mm]\\,", ",%m/%d/%Y %I:%M:%S %p,"], ["^\\w{3}\\s+\\d{2}\\s+\\d{2}:\\d{2}:\\d{2}", "%b %d %H:%M:%S"], ["\\d{2}/\\d{2}/\\d{4} \\d{2}:\\d{2}:\\d{2}", "%m/%d/%Y %H:%M:%S"], ["^\\d{2}\\/\\d{2}\\/\\d{2,4}\\s+\\d{2}:\\d{2}:\\d{2}\\s+[AaPp][Mm]", "%m/%d/%Y %I:%M:%S %p"], ["\\d{2}\\/\\d{2}\\/\\d{4}\\s\\d{2}:\\d{2}:\\d{2}", "%m-%d-%Y %H:%M:%S"], ["\\\"timestamp\\\":\\s\\\"(\\d+)", "%s"], ["\\d{2}\\/\\w+\\/\\d{4}\\s\\d{2}:\\d{2}:\\d{2}:\\d{3}", "%d-%b-%Y %H:%M:%S:%f"], ["\\\"created\\\":\\s(\\d+)", "%s"], ["\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}", "%Y-%m-%dT%H:%M:%S"], ["\\d{1,2}/\\w{3}/\\d{4}:\\d{2}:\\d{2}:\\d{2}:\\d{1,3}", "%d/%b/%Y:%H:%M:%S:%f"], ["\\d{1,2}/\\w{3}/\\d{4}:\\d{2}:\\d{2}:\\d{2}", "%d/%b/%Y:%H:%M:%S"]]
+
+token.0.token = \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
+token.0.replacementType = timestamp
+token.0.replacement = %Y-%m-%d %H:%M:%S
diff --git a/tests/small/test_main.py b/tests/small/test_main.py
index 6dda5007..3f68254d 100644
--- a/tests/small/test_main.py
+++ b/tests/small/test_main.py
@@ -1,23 +1,25 @@
#!/usr/bin/env python2
-import pytest
import os
import sys
-from mock import MagicMock, call, patch, mock_open
+
+import pytest
+from mock import MagicMock, patch
+
+from splunk_eventgen.__main__ import parse_cli_vars, parse_env_vars
FILE_DIR = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, os.path.join(FILE_DIR, "..", "..", ".."))
sys.path.insert(0, os.path.join(FILE_DIR, "..", "..", "..", "splunk_eventgen"))
-from splunk_eventgen.__main__ import parse_cli_vars, parse_env_vars
-@pytest.mark.parametrize(('config'),
- [
- # Empty config
- ({}),
- # Some elements already defined - function should override
- ({"AMQP_HOST": "guest", "AMQP_PASS": "guest"})
- ])
+@pytest.mark.parametrize(
+ ('config'),
+ [
+ # Empty config
+ ({}),
+ # Some elements already defined - function should override
+ ({"AMQP_HOST": "guest", "AMQP_PASS": "guest"})])
def test_parse_cli_vars(config):
args = MagicMock()
args.amqp_uri = "pyamqp://user:pass@host:port"
@@ -28,32 +30,34 @@ def test_parse_cli_vars(config):
args.amqp_pass = "world"
args.web_server_address = "0.0.0.:1111"
obj = parse_cli_vars(config, args)
- assert obj == { "AMQP_URI": "pyamqp://user:pass@host:port",
- "AMQP_HOST": "hostname",
- "AMQP_PORT": 8001,
- "AMQP_WEBPORT": 8000 ,
- "AMQP_USER": "hello",
- "AMQP_PASS": "world",
- "WEB_SERVER_ADDRESS": "0.0.0.:1111" }
+ assert obj == {
+ "AMQP_URI": "pyamqp://user:pass@host:port", "AMQP_HOST": "hostname", "AMQP_PORT": 8001, "AMQP_WEBPORT": 8000,
+ "AMQP_USER": "hello", "AMQP_PASS": "world", "WEB_SERVER_ADDRESS": "0.0.0.:1111"}
-@pytest.mark.parametrize(('env_vars'),
- [
- # No environment vars defined
- ({}),
- # All environemnt vars defined
- ({"EVENTGEN_AMQP_URI": "test", "EVENTGEN_AMQP_HOST": "host", "EVENTGEN_AMQP_PORT": 8000, "EVENTGEN_AMQP_WEBPORT": 8001, "EVENTGEN_AMQP_USER": "hello", "EVENTGEN_AMQP_PASS": "world", "EVENTGEN_WEB_SERVER_ADDR": "0.0.0.0:1111"})
- ])
+
+@pytest.mark.parametrize(
+ ('env_vars'),
+ [
+ # No environment vars defined
+ ({}),
+ # All environemnt vars defined
+ ({
+ "EVENTGEN_AMQP_URI": "test", "EVENTGEN_AMQP_HOST": "host", "EVENTGEN_AMQP_PORT": 8000,
+ "EVENTGEN_AMQP_WEBPORT": 8001, "EVENTGEN_AMQP_USER": "hello", "EVENTGEN_AMQP_PASS": "world",
+ "EVENTGEN_WEB_SERVER_ADDR": "0.0.0.0:1111"})])
def test_parse_env_vars(env_vars):
with patch("splunk_eventgen.__main__.os") as mock_os:
mock_os.environ = env_vars
obj = parse_env_vars()
- assert obj.keys() == ['AMQP_WEBPORT', 'AMQP_USER', 'AMQP_PASS', 'AMQP_PORT', 'AMQP_URI', 'WEB_SERVER_ADDRESS', 'AMQP_HOST']
+ assert obj.keys() == [
+ 'AMQP_WEBPORT', 'AMQP_USER', 'AMQP_PASS', 'AMQP_PORT', 'AMQP_URI', 'WEB_SERVER_ADDRESS', 'AMQP_HOST']
if env_vars:
# If enviroment vars are defined, let's make sure they are set instead of default values
assert obj["WEB_SERVER_ADDRESS"] == "0.0.0.0:1111"
assert obj["AMQP_HOST"] == "host"
assert obj["AMQP_PORT"] == 8000
+
def test_parse_env_vars_and_parse_cli_vars():
'''
This test checks the layering effect of both parsing CLI and env vars.
@@ -67,7 +71,7 @@ def test_parse_env_vars_and_parse_cli_vars():
assert obj["AMQP_PORT"] == 5672
assert obj["AMQP_PASS"] == "guest"
assert obj["AMQP_USER"] == "guest"
- assert obj["AMQP_URI"] == None
+ assert obj["AMQP_URI"] is None
assert obj["WEB_SERVER_ADDRESS"] == "0.0.0.0:9500"
args = MagicMock()
args.amqp_uri = "pyamqp://user:pass@host:port"
@@ -78,11 +82,7 @@ def test_parse_env_vars_and_parse_cli_vars():
# Purposely defining None vars here for these CLI args - in this case, environment vars will be used
args.amqp_user = None
args.amqp_pass = None
- newobj = parse_cli_vars(obj, args)
- assert obj == { "AMQP_URI": "pyamqp://user:pass@host:port",
- "AMQP_HOST": "hostname",
- "AMQP_PORT": 8001,
- "AMQP_WEBPORT": 8000 ,
- "AMQP_USER": "guest",
- "AMQP_PASS": "guest",
- "WEB_SERVER_ADDRESS": "0.0.0.:1111" }
+ parse_cli_vars(obj, args)
+ assert obj == {
+ "AMQP_URI": "pyamqp://user:pass@host:port", "AMQP_HOST": "hostname", "AMQP_PORT": 8001, "AMQP_WEBPORT":
+ 8000, "AMQP_USER": "guest", "AMQP_PASS": "guest", "WEB_SERVER_ADDRESS": "0.0.0.:1111"}
diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py
new file mode 100644
index 00000000..528209ef
--- /dev/null
+++ b/tests/unit/conftest.py
@@ -0,0 +1,17 @@
+from os import path as op
+
+import pytest
+
+from splunk_eventgen.lib.eventgenconfig import Config
+
+
+@pytest.fixture
+def eventgen_config():
+ """Returns a function to create config instance based on config file"""
+
+ def _make_eventgen_config_instance(configfile=None):
+ if configfile is not None:
+ configfile = op.join(op.dirname(op.dirname(__file__)), 'sample_eventgen_conf', 'unit', configfile)
+ return Config(configfile=configfile)
+
+ return _make_eventgen_config_instance
diff --git a/tests/unit/test_eventgenconfig.py b/tests/unit/test_eventgenconfig.py
new file mode 100644
index 00000000..b0391ef6
--- /dev/null
+++ b/tests/unit/test_eventgenconfig.py
@@ -0,0 +1,277 @@
+import json
+import os
+from ConfigParser import ConfigParser
+
+import pytest
+
+from splunk_eventgen.lib.eventgensamples import Sample
+
+
+def test_makeSplunkEmbedded(eventgen_config):
+ """Test makeSplunkEmbedded works"""
+ config_instance = eventgen_config()
+ session_key = 'ea_IO86v01Xipz8BuB_Ako9rMoc5_HNn6UQrBhVQY5zj68LN2J2xVrLzYD^XEgVTWyKrXva6r8yZ2gtEuv9nnZ'
+ config_instance.makeSplunkEmbedded(session_key)
+ assert config_instance.splunkEmbedded
+ # reset splunkEmbedded since all instances share the attribute
+ config_instance.splunkEmbedded = False
+
+
+def test_buildConfDict(eventgen_config):
+ """Test buildConfDict returns the same as reading directly from file"""
+ config_instance = eventgen_config()
+ config_instance._buildConfDict()
+ configparser = ConfigParser()
+ splunk_eventgen_folder = os.path.join(
+ os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), 'splunk_eventgen')
+ configparser.read(os.path.join(splunk_eventgen_folder, 'default', 'eventgen.conf'))
+ configparser.set('global', 'eai:acl', {'app': 'splunk_eventgen'})
+
+ for key, value in config_instance._confDict['global'].items():
+ assert value == configparser.get('global', key)
+
+
+def test_validate_setting_count(eventgen_config):
+ """Test count config is int with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ assert type(config_instance._validateSetting('sample', 'count', '0')) == int
+ assert config_instance._validateSetting('sample', 'count', '0') == 0
+
+
+def test_validate_setting_delay(eventgen_config):
+ """Test delay config is int with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ assert type(config_instance._validateSetting('sample', 'delay', '10')) == int
+ assert config_instance._validateSetting('sample', 'delay', '10') == 10
+
+
+def test_validate_setting_interval(eventgen_config):
+ """Test interval config is int with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ assert type(config_instance._validateSetting('sample', 'interval', '3')) == int
+ assert config_instance._validateSetting('sample', 'interval', '3') == 3
+
+
+def test_validate_setting_perdayvolume(eventgen_config):
+ """Test perdayvolume config is float with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ assert type(config_instance._validateSetting('sample', 'perDayVolume', '1')) == float
+ assert config_instance._validateSetting('sample', 'perDayVolume', '1') == 1.0
+
+
+def test_validate_setting_randomizeCount(eventgen_config):
+ """Test randomizeCount config is float with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ assert type(config_instance._validateSetting('sample', 'randomizeCount', '0.2')) == float
+ assert config_instance._validateSetting('sample', 'randomizeCount', '0.2') == 0.2
+
+
+def test_validate_setting_timeMultiple(eventgen_config):
+ """Test timeMultiple config is float with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ assert type(config_instance._validateSetting('sample', 'timeMultiple', '2')) == float
+ assert config_instance._validateSetting('sample', 'timeMultiple', '2') == 2.0
+
+
+def test_validate_setting_disabled(eventgen_config):
+ """Test disabled config is bool with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ assert type(config_instance._validateSetting('sample', 'disabled', 'false')) == bool
+ assert config_instance._validateSetting('sample', 'disabled', 'false') is False
+
+
+def test_validate_setting_profiler(eventgen_config):
+ """Test profiler config is bool with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ assert type(config_instance._validateSetting('sample', 'profiler', 'false')) == bool
+ assert config_instance._validateSetting('sample', 'profiler', 'false') is False
+
+
+def test_validate_setting_useOutputQueue(eventgen_config):
+ """Test useOutputQueue config is bool with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ assert type(config_instance._validateSetting('sample', 'useOutputQueue', 'false')) == bool
+ assert config_instance._validateSetting('sample', 'useOutputQueue', 'false') is False
+
+
+def test_validate_setting_bundlelines(eventgen_config):
+ """Test bundlelines config is bool with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ assert type(config_instance._validateSetting('sample', 'bundlelines', 'false')) == bool
+ assert config_instance._validateSetting('sample', 'bundlelines', 'false') is False
+
+
+def test_validate_setting_httpeventWaitResponse(eventgen_config):
+ """Test httpeventWaitResponse config is bool with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ assert type(config_instance._validateSetting('sample', 'httpeventWaitResponse', 'false')) == bool
+ assert config_instance._validateSetting('sample', 'httpeventWaitResponse', 'false') is False
+
+
+def test_validate_setting_sequentialTimestamp(eventgen_config):
+ """Test sequentialTimestamp config is bool with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ assert type(config_instance._validateSetting('sample', 'sequentialTimestamp', 'false')) == bool
+ assert config_instance._validateSetting('sample', 'sequentialTimestamp', 'false') is False
+
+
+def test_validate_setting_autotimestamp(eventgen_config):
+ """Test autotimestamp config is bool with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ assert type(config_instance._validateSetting('sample', 'autotimestamp', 'false')) == bool
+ assert config_instance._validateSetting('sample', 'autotimestamp', 'false') is False
+
+
+def test_validate_setting_randomizeEvents(eventgen_config):
+ """Test randomizeEvents config is bool with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ assert type(config_instance._validateSetting('sample', 'randomizeEvents', 'false')) == bool
+ assert config_instance._validateSetting('sample', 'randomizeEvents', 'false') is False
+
+
+def test_validate_setting_outputCounter(eventgen_config):
+ """Test outputCounter config is bool with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ assert type(config_instance._validateSetting('sample', 'outputCounter', 'false')) == bool
+ assert config_instance._validateSetting('sample', 'outputCounter', 'false') is False
+
+
+def test_validate_setting_minuteOfHourRate(eventgen_config):
+ """Test minuteOfHourRate config is dict with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ minuteOfHourRate = '{ "0": 1, "1": 1, "2": 1, "3": 1, "4": 1, "5": 1, "6": 1, "7": 1, "8": 1, "9": 1,' \
+ ' "10": 1, "11": 1, "12": 1, "13": 1, "14": 1, "15": 1, "16": 1, "17": 1, "18": 1,' \
+ ' "19": 1, "20": 1, "21": 1, "22": 1, "23": 1, "24": 1, "25": 1, "26": 1, "27": 1,' \
+ ' "28": 1, "29": 1, "30": 1, "31": 1, "32": 1, "33": 1, "34": 1, "35": 4, "36": 0.1,' \
+ ' "37": 0.1, "38": 1, "39": 1, "40": 1, "41": 1, "42": 1, "43": 1, "44": 1, "45": 1,' \
+ ' "46": 1, "47": 1, "48": 1, "49": 1, "50": 1, "51": 1, "52": 1, "53": 1, "54": 1,' \
+ ' "55": 1, "56": 1, "57": 1, "58": 1, "59": 1 }'
+ assert type(config_instance._validateSetting('sample', 'minuteOfHourRate', minuteOfHourRate)) == dict
+ result = json.loads(minuteOfHourRate)
+ assert config_instance._validateSetting('sample', 'minuteOfHourRate', minuteOfHourRate) == result
+
+
+def test_validate_setting_hourOfDayRate(eventgen_config):
+ """Test hourOfDayRate config is dict with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ hourOfDayRate = '{ "0": 0.30, "1": 0.20, "2": 0.20, "3": 0.20, "4": 0.20, "5": 0.25, "6": 0.35, "7": 0.50,' \
+ ' "8": 0.60, "9": 0.65, "10": 0.70, "11": 0.75, "12": 0.77, "13": 0.80, "14": 0.82,' \
+ ' "15": 0.85, "16": 0.87, "17": 0.90, "18": 0.95, "19": 1.0, "20": 0.85, "21": 0.70,' \
+ ' "22": 0.60, "23": 0.45 }'
+ assert type(config_instance._validateSetting('sample', 'hourOfDayRate', hourOfDayRate)) == dict
+ result = json.loads(hourOfDayRate)
+ assert config_instance._validateSetting('sample', 'hourOfDayRate', hourOfDayRate) == result
+
+
+def test_validate_setting_dayOfWeekRate(eventgen_config):
+ """Test dayOfWeekRate config is dict with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ dayOfWeekRate = '{ "0": 0.97, "1": 0.95, "2": 0.90, "3": 0.97, "4": 1.0, "5": 0.99, "6": 0.55 }'
+ assert type(config_instance._validateSetting('sample', 'dayOfWeekRate', dayOfWeekRate)) == dict
+ result = json.loads(dayOfWeekRate)
+ assert config_instance._validateSetting('sample', 'dayOfWeekRate', dayOfWeekRate) == result
+
+
+def test_validate_setting_dayOfMonthRate(eventgen_config):
+ """Test dayOfMonthRate config is dict with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ dayOfMonthRate = '{ "1": 1, "2": 1, "3": 1, "4": 1, "5": 1, "6": 1, "7": 1, "8": 1, "9": 1, "10": 1,' \
+ ' "11": 1, "12": 1, "13": 1, "14": 1, "15": 1, "16": 1, "17": 1, "18": 1, "19": 1, "20": 1,' \
+ ' "21": 1, "22": 1, "23": 1, "24": 1, "25": 1, "26": 1, "27": 1, "28": 1, "29": 1, "30": 1,' \
+ ' "31": 1 }'
+ assert type(config_instance._validateSetting('sample', 'dayOfMonthRate', dayOfMonthRate)) == dict
+ result = json.loads(dayOfMonthRate)
+ assert config_instance._validateSetting('sample', 'dayOfMonthRate', dayOfMonthRate) == result
+
+
+def test_validate_setting_monthOfYearRate(eventgen_config):
+ """Test monthOfYearRate config is dict with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ monthOfYearRate = '{ "1": 1, "2": 1, "3": 1, "4": 1, "5": 1, "6": 1, "7": 1,' \
+ ' "8": 1, "9": 1, "10": 1, "11": 1, "12": 1 }'
+ assert type(config_instance._validateSetting('sample', 'monthOfYearRate', monthOfYearRate)) == dict
+ result = json.loads(monthOfYearRate)
+ assert config_instance._validateSetting('sample', 'monthOfYearRate', monthOfYearRate) == result
+
+
+def test_validate_setting_httpeventServers(eventgen_config):
+ """Test httpeventServers config is dict with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ httpeventServers = '{"servers":[{ "protocol":"https", "address":"127.0.0.1",' \
+ ' "port":"8088", "key":"8d5ab52c-3759-49e3-b66a-5213ce525692"}]}'
+ assert type(config_instance._validateSetting('sample', 'httpeventServers', httpeventServers)) == dict
+ result = json.loads(httpeventServers)
+ assert config_instance._validateSetting('sample', 'httpeventServers', httpeventServers) == result
+
+
+def test_validate_setting_autotimestamps(eventgen_config):
+ """Test autotimestamps config is dict with right value"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ autotimestamps = r'[["\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}", "%Y-%m-%d %H:%M:%S"], ' \
+ r'["\\d{1,2}\\/\\w{3}\\/\\d{4}\\s\\d{2}:\\d{2}:\\d{2}:\\d{1,3}", "%d/%b/%Y %H:%M:%S:%f"], ' \
+ r'["\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}", "%Y-%m-%dT%H:%M:%S.%f"], ' \
+ r'["\\d{1,2}/\\w{3}/\\d{4}\\s\\d{2}:\\d{2}:\\d{2}:\\d{1,3}", "%d/%b/%Y %H:%M:%S:%f"], ' \
+ r'["\\d{1,2}/\\d{2}/\\d{2}\\s\\d{1,2}:\\d{2}:\\d{2}", "%m/%d/%y %H:%M:%S"], ' \
+ r'["\\d{2}-\\d{2}-\\d{4} \\d{2}:\\d{2}:\\d{2}", "%m-%d-%Y %H:%M:%S"], ' \
+ r'["\\w{3} \\w{3} +\\d{1,2} \\d{2}:\\d{2}:\\d{2}", "%a %b %d %H:%M:%S"], ' \
+ r'["\\w{3} \\w{3} \\d{2} \\d{4} \\d{2}:\\d{2}:\\d{2}", "%a %b %d %Y %H:%M:%S"], ' \
+ r'["^(\\w{3}\\s+\\d{1,2}\\s\\d{2}:\\d{2}:\\d{2})", "%b %d %H:%M:%S"], ' \
+ r'["(\\w{3}\\s+\\d{1,2}\\s\\d{1,2}:\\d{1,2}:\\d{1,2})", "%b %d %H:%M:%S"], ' \
+ r'["(\\w{3}\\s\\d{1,2}\\s\\d{1,4}\\s\\d{1,2}:\\d{1,2}:\\d{1,2})", "%b %d %Y %H:%M:%S"], ' \
+ r'["\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3}", "%Y-%m-%d %H:%M:%S.%f"], ' \
+ r'["\\,\\d{2}\\/\\d{2}\\/\\d{2,4}\\s+\\d{2}:\\d{2}:\\d{2}\\s+[AaPp][Mm]\\,", ' \
+ r'",%m/%d/%Y %I:%M:%S %p,"], ' \
+ r'["^\\w{3}\\s+\\d{2}\\s+\\d{2}:\\d{2}:\\d{2}", "%b %d %H:%M:%S"], ' \
+ r'["\\d{2}/\\d{2}/\\d{4} \\d{2}:\\d{2}:\\d{2}", "%m/%d/%Y %H:%M:%S"], ' \
+ r'["^\\d{2}\\/\\d{2}\\/\\d{2,4}\\s+\\d{2}:\\d{2}:\\d{2}\\s+[AaPp][Mm]", "%m/%d/%Y %I:%M:%S %p"],' \
+ r'["\\d{2}\\/\\d{2}\\/\\d{4}\\s\\d{2}:\\d{2}:\\d{2}", "%m-%d-%Y %H:%M:%S"], ' \
+ r'["\\\"timestamp\\\":\\s\\\"(\\d+)", "%s"], ' \
+ r'["\\d{2}\\/\\w+\\/\\d{4}\\s\\d{2}:\\d{2}:\\d{2}:\\d{3}", "%d-%b-%Y %H:%M:%S:%f"], ' \
+ r'["\\\"created\\\":\\s(\\d+)", "%s"], ["\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}", ' \
+ r'"%Y-%m-%dT%H:%M:%S"], ' \
+ r'["\\d{1,2}/\\w{3}/\\d{4}:\\d{2}:\\d{2}:\\d{2}:\\d{1,3}", "%d/%b/%Y:%H:%M:%S:%f"], ' \
+ r'["\\d{1,2}/\\w{3}/\\d{4}:\\d{2}:\\d{2}:\\d{2}", "%d/%b/%Y:%H:%M:%S"]]'
+ assert type(config_instance._validateSetting('sample', 'autotimestamps', autotimestamps)) == list
+ result = json.loads(autotimestamps)
+ assert config_instance._validateSetting('sample', 'autotimestamps', autotimestamps) == result
+
+
+def test_getPlugin(eventgen_config):
+ """Test getPlugin method without loading any plugins"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ with pytest.raises(KeyError):
+ config_instance.getPlugin('output.awss3')
+
+
+def test_getSplunkUrl(eventgen_config):
+ """Test getSplunkUrl with provided sample object"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ sample = Sample('test')
+ sample.splunkHost = 'localhost'
+ sample.splunkMethod = 'https'
+ sample.splunkPort = '8088'
+
+ assert ('https://localhost:8088', 'https', 'localhost', '8088') == config_instance.getSplunkUrl(sample)
+
+
+def test_validateTimeZone(eventgen_config):
+ """Test _validateTimeZone method"""
+ pass
+
+
+def test_validateSeed(eventgen_config):
+ """Test _validateSeed method"""
+ pass
+
+
+def test_punct(eventgen_config):
+ """Test _punct method with given string"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ assert '--:\n$^' == config_instance._punct('this-is-a: test \ntest $^')
+
+
+def test_parse(eventgen_config):
+ """Test parse method with given evengen config"""
+ config_instance = eventgen_config(configfile='eventgen.conf.config')
+ config_instance.parse()
+ assert len(config_instance.samples) == 1
diff --git a/tests/unit/test_timeparser.py b/tests/unit/test_timeparser.py
new file mode 100644
index 00000000..4dc7d13d
--- /dev/null
+++ b/tests/unit/test_timeparser.py
@@ -0,0 +1,105 @@
+import datetime
+
+import pytest
+
+from splunk_eventgen.lib import timeparser
+
+time_delta_test_params = [(datetime.timedelta(days=1), 86400),
+ (datetime.timedelta(days=1, hours=3, minutes=15, seconds=32), 98132),
+ (datetime.timedelta(hours=1, minutes=10), 4200), (datetime.timedelta(hours=-1), -3600),
+ (None, 0)]
+
+
+@pytest.mark.parametrize('delta,expect', time_delta_test_params)
+def test_time_delta_2_second(delta, expect):
+ ''' Test timeDelta2secs function, convert time delta object to seconds
+ Normal cases:
+ case 1: time delta is 1 day, expect is 86400
+ case 2: time delta is 1 day 3 hour 15 minutes 32 seconds, expect is 98132
+ case 3: time delta is less than 1 day, only 1 hour 10 minutes, expect is 4200
+ case 4: time delta is 1 hour ago, expect is -3600
+
+ Corner cases:
+ case 1: delta object is None -- invalid input, expect is
+ '''
+ assert timeparser.timeDelta2secs(delta) == expect
+
+
+def check_datetime_equal(d1, d2):
+ assert d1.year == d2.year
+ assert d1.month == d2.month
+ assert d1.day == d2.day
+ assert d1.hour == d2.hour
+ assert d1.minute == d2.minute
+ assert d1.second == d2.second
+
+
+parse_time_math_params = [('+', '100', 's', datetime.datetime(2019, 3, 8, 4, 10, 20),
+ datetime.datetime(2019, 3, 8, 4, 12, 0)),
+ ('-', '20', 'm', datetime.datetime(2019, 3, 8, 4, 10, 20),
+ datetime.datetime(2017, 7, 8, 4, 10, 20)),
+ ('', '3', 'w', datetime.datetime(2019, 3, 8, 4, 10, 20),
+ datetime.datetime(2019, 3, 29, 4, 10, 20)),
+ ('', '0', 's', datetime.datetime(2019, 3, 8, 4, 10, 20),
+ datetime.datetime(2019, 3, 8, 4, 10, 20)),
+ ('', '123', '', datetime.datetime(2019, 3, 8, 4, 10, 20),
+ datetime.datetime(2019, 3, 8, 4, 10, 20))]
+
+
+@pytest.mark.parametrize('plusminus,num,unit,ret,expect', parse_time_math_params)
+def test_time_parser_time_math(plusminus, num, unit, ret, expect):
+ '''
+ test timeParserTimeMath function, parse the time modifier
+ Normal Case:
+ Case 1: input "+100s" -- the parser should translate it as 100 seconds later.
+ Case 2: input "-20m" -- the parser should handle the month larger than 12 and translate as 20 months ago
+ Case 3: input '3w' -- the parser should translate as 21 days later.
+
+ Corner Cases:
+ Case 1: input "0s" -- the time parser should return now
+ Case 2: input "123" -- unit is the empty string, behavior
+ '''
+ check_datetime_equal(timeparser.timeParserTimeMath(plusminus, num, unichr, ret), expect)
+
+
+def mock_now():
+ return datetime.datetime(2019, 3, 10, 13, 20, 15)
+
+
+def mock_utc_now():
+ return datetime.datetime(2019, 3, 10, 5, 20, 15)
+
+
+timeparser_params = [
+ ('now', datetime.timedelta(days=1), datetime.datetime(2019, 3, 10, 13, 20, 15)),
+ ('now', datetime.timedelta(days=0), datetime.datetime(2019, 3, 10, 5, 20, 15)),
+ ('now', datetime.timedelta(hours=2), datetime.datetime(2019, 3, 10, 7, 20, 15)),
+ ('now', datetime.timedelta(hours=-3), datetime.datetime(2019, 3, 10, 2, 20, 15)),
+ ('-7d', datetime.timedelta(days=1), datetime.datetime(2019, 3, 3, 13, 20, 15)),
+ ('-0mon@mon', datetime.timedelta(days=1), datetime.datetime(2019, 3, 1, 0, 0, 0)),
+ ('-1mon@mon', datetime.timedelta(days=1), datetime.datetime(2019, 2, 1, 0, 0, 0)),
+ ('-3d@d', datetime.timedelta(days=1), datetime.datetime(2019, 3, 7, 0, 0, 0)),
+ ('+5d', datetime.timedelta(days=1), datetime.datetime(2019, 3, 15, 13, 20, 15)),
+ ('', datetime.timedelta(days=1), datetime.datetime(2019, 3, 10, 13, 20, 15)), ]
+
+
+@pytest.mark.parametrize('ts,tz,expect', timeparser_params)
+def test_timeparser(ts, tz, expect):
+ '''
+ test timeParser function, parse splunk time modifier
+ Normal Cases:
+ Case 1: get now timestamp
+ Case 2: get utc now timestamp
+ Case 3: get utc+2 timezone timestamp
+ Case 4: get utc-2 timezone timestamp
+ Case 5: get the 7 days ago timestamp
+ Case 5: get the beginning of this month. check the snap to month
+ Case 6: get the beginning of last month. check the snap to last month
+ Case 7: get 3 days ago, snap to day
+ Case 8: get 5 days later
+
+ Corner Cases:
+ Case 1: empty string as input. behavior
+ '''
+ r = timeparser.timeParser(ts, tz, mock_now, mock_utc_now)
+ check_datetime_equal(r, expect)