text:
require "google/cloud/bigquery/service"
require "google/cloud/bigquery/data"
require "google/cloud/bigquery/encryption_configuration"
require "google/apis/bigquery_v2"

module Google
  module Cloud
    module Bigquery
      ##
      # # QueryJob
      #
      # A {Job} subclass representing a query operation that may be performed
      # on a {Table}. A QueryJob instance is created when you call
      # {Project#query_job}, {Dataset#query_job}.
      #
      # @see https://cloud.google.com/bigquery/querying-data Querying Data
      # @see https://cloud.google.com/bigquery/docs/reference/v2/jobs Jobs API
      #   reference
      #
      # @example
      #   require "google/cloud/bigquery"
      #
      #   bigquery = Google::Cloud::Bigquery.new
      #
      #   job = bigquery.query_job "SELECT COUNT(word) as count FROM " \
      #                            "`bigquery-public-data.samples.shakespeare`"
      #
      #   job.wait_until_done!
      #
      #   if job.failed?
      #     puts job.error
      #   else
      #     puts job.data.first
      #   end
      #
      class QueryJob < Job
        ##
        # Checks if the priority for the query is `BATCH`.
        #
        # @return [Boolean] `true` when the priority is `BATCH`, `false`
        #   otherwise.
        #
        def batch?
          val = @gapi.configuration.query.priority
          val == "BATCH"
        end

        ##
        # Checks if the priority for the query is `INTERACTIVE`.
        #
        # @return [Boolean] `true` when the priority is `INTERACTIVE`, `false`
        #   otherwise.
        #
        def interactive?
          val = @gapi.configuration.query.priority
          return true if val.nil?
          val == "INTERACTIVE"
        end

        ##
        # Checks if the the query job allows arbitrarily large results at a
        # slight cost to performance.
        #
        # @return [Boolean] `true` when large results are allowed, `false`
        #   otherwise.
        #
        def large_results?
          val = @gapi.configuration.query.allow_large_results
          return false if val.nil?
          val
        end

        ##
        # Checks if the query job looks for an existing result in the query
        # cache. For more information, see [Query
        # Caching](https://cloud.google.com/bigquery/querying-data#querycaching).
        #
        # @return [Boolean] `true` when the query cache will be used, `false`
        #   otherwise.
        #
        def cache?
          val = @gapi.configuration.query.use_query_cache
          return false if val.nil?
          val
        end

        ##
        # If set, don't actually run this job. A valid query will return a
        # mostly empty response with some processing statistics, while an
        # invalid query will return the same error it would if it wasn't a dry
        # run.
        #
        # @return [Boolean] `true` when the dry run flag is set for the query
        #   job, `false` otherwise.
        #
        def dryrun?
          @gapi.configuration.dry_run
        end
        alias dryrun dryrun?
        alias dry_run dryrun?
        alias dry_run? dryrun?

        ##
        # Checks if the query job flattens nested and repeated fields in the
        # query results. The default is `true`. If the value is `false`,
        # #large_results? should return `true`.
        #
        # @return [Boolean] `true` when the job flattens results, `false`
        #   otherwise.
        #
        def flatten?
          val = @gapi.configuration.query.flatten_results
          return true if val.nil?
          val
        end

        ##
        # Limits the billing tier for this job. Queries that have resource usage
        # beyond this tier will raise (without incurring a charge). If
        # unspecified, this will be set to your project default. For more
        # information, see [High-Compute
        # queries](https://cloud.google.com/bigquery/pricing#high-compute).
        #
        # @return [Integer, nil] The tier number, or `nil` for the project
        #   default.
        #
        def maximum_billing_tier
          @gapi.configuration.query.maximum_billing_tier
        end

        ##
        # Limits the bytes billed for this job. Queries that will have bytes
        # billed beyond this limit will raise (without incurring a charge). If
        # `nil`, this will be set to your project default.
        #
        # @return [Integer, nil] The number of bytes, or `nil` for the project
        #   default.
        #
        def maximum_bytes_billed
          Integer @gapi.configuration.query.maximum_bytes_billed
        rescue StandardError
          nil
        end

        ##
        # Checks if the query results are from the query cache.
        #
        # @return [Boolean] `true` when the job statistics indicate a cache hit,
        #   `false` otherwise.
        #
        def cache_hit?
          return false unless @gapi.statistics.query
          @gapi.statistics.query.cache_hit
        end

        ##
        # The number of bytes processed by the query.
        #
        # @return [Integer, nil] Total bytes processed for the job.
        #
        def bytes_processed
          Integer @gapi.statistics.query.total_bytes_processed
        rescue StandardError
          nil
        end

        ##
        # Describes the execution plan for the query.
        #
        # @return [Array<Google::Cloud::Bigquery::QueryJob::Stage>, nil] An
        #   array containing the stages of the execution plan.
        #
        # @example
        #   require "google/cloud/bigquery"
        #
        #   bigquery = Google::Cloud::Bigquery.new
        #
        #   sql = "SELECT word FROM `bigquery-public-data.samples.shakespeare`"
        #   job = bigquery.query_job sql
        #
        #   job.wait_until_done!
        #
        #   stages = job.query_plan
        #   stages.each do |stage|
        #     puts stage.name
        #     stage.steps.each do |step|
        #       puts step.kind
        #       puts step.substeps.inspect
        #     end
        #   end
        #
        def query_plan
          return nil unless @gapi.statistics.query &&
                            @gapi.statistics.query.query_plan
          Array(@gapi.statistics.query.query_plan).map do |stage|
            Stage.from_gapi stage
          end
        end

        ##
        # The type of query statement, if valid. Possible values (new values
        # might be added in the future):
        #
        # * "CREATE_MODEL": DDL statement, see [Using Data Definition Language
        #   Statements](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language)
        # * "CREATE_TABLE": DDL statement, see [Using Data Definition Language
        #   Statements](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language)
        # * "CREATE_TABLE_AS_SELECT": DDL statement, see [Using Data Definition
        #   Language Statements](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language)
        # * "CREATE_VIEW": DDL statement, see [Using Data Definition Language
        #   Statements](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language)
        # * "DELETE": DML statement, see [Data Manipulation Language Syntax](https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax)
        # * "DROP_MODEL": DDL statement, see [Using Data Definition Language
        #   Statements](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language)
        # * "DROP_TABLE": DDL statement, see [Using Data Definition Language
        #   Statements](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language)
        # * "DROP_VIEW": DDL statement, see [Using Data Definition Language
        #   Statements](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language)
        # * "INSERT": DML statement, see [Data Manipulation Language Syntax](https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax)
        # * "MERGE": DML statement, see [Data Manipulation Language Syntax](https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax)
        # * "SELECT": SQL query, see [Standard SQL Query Syntax](https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax)
        # * "UPDATE": DML statement, see [Data Manipulation Language Syntax](https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax)
        #
        # @return [String, nil] The type of query statement.
        #
        def statement_type
          return nil unless @gapi.statistics.query
          @gapi.statistics.query.statement_type
        end

        ##
        # Whether the query is a DDL statement.
        #
        # @see https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language
        #   Using Data Definition Language Statements
        #
        # @return [Boolean]
        #
        # @example
        #   require "google/cloud/bigquery"
        #
        #   bigquery = Google::Cloud::Bigquery.new
        #   query_job = bigquery.query_job "CREATE TABLE my_table (x INT64)"
        #
        #   query_job.statement_type #=> "CREATE_TABLE"
        #   query_job.ddl? #=> true
        #
        def ddl?
          %w[CREATE_MODEL CREATE_TABLE CREATE_TABLE_AS_SELECT CREATE_VIEW \
             DROP_MODEL DROP_TABLE DROP_VIEW].include? statement_type
        end

        ##
        # Whether the query is a DML statement.
        #
        # @see https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax
        #   Data Manipulation Language Syntax
        #
        # @return [Boolean]
        #
        # @example
        #   require "google/cloud/bigquery"
        #
        #   bigquery = Google::Cloud::Bigquery.new
        #   query_job = bigquery.query_job "UPDATE my_table " \
        #                                  "SET x = x + 1 " \
        #                                  "WHERE x IS NOT NULL"
        #
        #   query_job.statement_type #=> "UPDATE"
        #   query_job.dml? #=> true
        #
        def dml?
          %w[INSERT UPDATE MERGE DELETE].include? statement_type
        end

        ##
        # The DDL operation performed, possibly dependent on the pre-existence
        # of the DDL target. (See {#ddl_target_table}.) Possible values (new
        # values might be added in the future):
        #
        # * "CREATE": The query created the DDL target.
        # * "SKIP": No-op. Example cases: the query is
        #   `CREATE TABLE IF NOT EXISTS` while the table already exists, or the
        #   query is `DROP TABLE IF EXISTS` while the table does not exist.
        # * "REPLACE": The query replaced the DDL target. Example case: the
        #   query is `CREATE OR REPLACE TABLE`, and the table already exists.
        # * "DROP": The query deleted the DDL target.
        #
        # @return [String, nil] The DDL operation performed.
        #
        def ddl_operation_performed
          return nil unless @gapi.statistics.query
          @gapi.statistics.query.ddl_operation_performed
        end

        ##
        # The DDL target table, in reference state. (See {Table#reference?}.)
        # Present only for `CREATE/DROP TABLE/VIEW` queries. (See
        # {#statement_type}.)
        #
        # @return [Google::Cloud::Bigquery::Table, nil] The DDL target table, in
        #   reference state.
        #
        def ddl_target_table
          return nil unless @gapi.statistics.query
          ensure_service!
          table = @gapi.statistics.query.ddl_target_table
          return nil unless table
          Google::Cloud::Bigquery::Table.new_reference_from_gapi table, service
        end

        ##
        # The number of rows affected by a DML statement. Present only for DML
        # statements `INSERT`, `UPDATE` or `DELETE`. (See {#statement_type}.)
        #
        # @return [Integer, nil] The number of rows affected by a DML statement,
        #   or `nil` if the query is not a DML statement.
        #
        def num_dml_affected_rows
          return nil unless @gapi.statistics.query
          @gapi.statistics.query.num_dml_affected_rows
        end

        ##
        # The table in which the query results are stored.
        #
        # @return [Table] A table instance.
        #
        def destination
          table = @gapi.configuration.query.destination_table
          return nil unless table
          retrieve_table table.project_id,
                         table.dataset_id,
                         table.table_id
        end

        ##
        # Checks if the query job is using legacy sql.
        #
        # @return [Boolean] `true` when legacy sql is used, `false` otherwise.
        #
        def legacy_sql?
          val = @gapi.configuration.query.use_legacy_sql
          return true if val.nil?
          val
        end

        ##
        # Checks if the query job is using standard sql.
        #
        # @return [Boolean] `true` when standard sql is used, `false` otherwise.
        #
        def standard_sql?
          !legacy_sql?
        end

        ##
        # The user-defined function resources used in the query. May be either a
        # code resource to load from a Google Cloud Storage URI
        # (`gs://bucket/path`), or an inline resource that contains code for a
        # user-defined function (UDF). Providing an inline code resource is
        # equivalent to providing a URI for a file containing the same code. See
        # [User-Defined Functions](https://cloud.google.com/bigquery/docs/reference/standard-sql/user-defined-functions).
        #
        # @return [Array<String>] An array containing Google Cloud Storage URIs
        #   and/or inline source code.
        #
        def udfs
          udfs_gapi = @gapi.configuration.query.user_defined_function_resources
          return nil unless udfs_gapi
          Array(udfs_gapi).map do |udf|
            udf.inline_code || udf.resource_uri
          end
        end

        ##
        # The encryption configuration of the destination table.
        #
        # @return [Google::Cloud::BigQuery::EncryptionConfiguration] Custom
        #   encryption configuration (e.g., Cloud KMS keys).
        #
        # @!group Attributes
        def encryption
          EncryptionConfiguration.from_gapi(
            @gapi.configuration.query.destination_encryption_configuration
          )
        end

        ###
        # Checks if the destination table will be time-partitioned. See
        # [Partitioned Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
        #
        # @return [Boolean, nil] `true` when the table will be time-partitioned,
        #   or `false` otherwise.
        #
        # @!group Attributes
        #
        def time_partitioning?
          !@gapi.configuration.query.time_partitioning.nil?
        end

        ###
        # The period for which the destination table will be partitioned, if
        # any. See [Partitioned Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
        #
        # @return [String, nil] The partition type. Currently the only supported
        #   value is "DAY", or `nil` if not present.
        #
        # @!group Attributes
        #
        def time_partitioning_type
          @gapi.configuration.query.time_partitioning.type if time_partitioning?
        end

        ###
        # The field on which the destination table will be partitioned, if any.
        # If not set, the destination table will be partitioned by pseudo column
        # `_PARTITIONTIME`; if set, the table will be partitioned by this field.
        # See [Partitioned Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
        #
        # @return [String, nil] The partition field, if a field was configured.
        #   `nil` if not partitioned or not set (partitioned by pseudo column
        #   '_PARTITIONTIME').
        #
        # @!group Attributes
        #
        def time_partitioning_field
          return nil unless time_partitioning?
          @gapi.configuration.query.time_partitioning.field
        end

        ###
        # The expiration for the destination table partitions, if any, in
        # seconds. See [Partitioned
        # Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
        #
        # @return [Integer, nil] The expiration time, in seconds, for data in
        #   partitions, or `nil` if not present.
        #
        # @!group Attributes
        #
        def time_partitioning_expiration
          tp = @gapi.configuration.query.time_partitioning
          tp.expiration_ms / 1_000 if tp && !tp.expiration_ms.nil?
        end

        ###
        # If set to true, queries over the destination table will require a
        # partition filter that can be used for partition elimination to be
        # specified. See [Partitioned
        # Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
        #
        # @return [Boolean] `true` when a partition filter will be required,
        #   or `false` otherwise.
        #
        # @!group Attributes
        #
        def time_partitioning_require_filter?
          tp = @gapi.configuration.query.time_partitioning
          return false if tp.nil? || tp.require_partition_filter.nil?
          tp.require_partition_filter
        end

        ###
        # Checks if the destination table will be clustered.
        #
        # @see https://cloud.google.com/bigquery/docs/clustered-tables
        #   Introduction to Clustered Tables
        #
        # @return [Boolean, nil] `true` when the table will be clustered,
        #   or `false` otherwise.
        #
        # @!group Attributes
        #
        def clustering?
          !@gapi.configuration.query.clustering.nil?
        end

        ###
        # One or more fields on which the destination table should be clustered.
        # Must be specified with time-based partitioning, data in the table will
        # be first partitioned and subsequently clustered. The order of the
        # returned fields determines the sort order of the data.
        #
        # See {QueryJob::Updater#clustering_fields=}.
        #
        # @see https://cloud.google.com/bigquery/docs/partitioned-tables
        #   Partitioned Tables
        # @see https://cloud.google.com/bigquery/docs/clustered-tables
        #   Introduction to Clustered Tables
        # @see https://cloud.google.com/bigquery/docs/creating-clustered-tables
        #   Creating and Using Clustered Tables
        #
        # @return [Array<String>, nil] The clustering fields, or `nil` if the
        #   destination table will not be clustered.
        #
        # @!group Attributes
        #
        def clustering_fields
          @gapi.configuration.query.clustering.fields if clustering?
        end

        ##
        # Refreshes the job until the job is `DONE`.
        # The delay between refreshes will incrementally increase.
        #
        # @example
        #   require "google/cloud/bigquery"
        #
        #   bigquery = Google::Cloud::Bigquery.new
        #
        #   sql = "SELECT word FROM `bigquery-public-data.samples.shakespeare`"
        #   job = bigquery.query_job sql
        #
        #   job.wait_until_done!
        #   job.done? #=> true
        #
        def wait_until_done!
          return if done?

          ensure_service!
          loop do
            query_results_gapi = service.job_query_results \
              job_id, location: location, max: 0
            if query_results_gapi.job_complete
              @destination_schema_gapi = query_results_gapi.schema
              break
            end
          end
          reload!
        end

        ##
        # Retrieves the query results for the job.
        #
        # @param [String] token Page token, returned by a previous call,
        #   identifying the result set.
        # @param [Integer] max Maximum number of results to return.
        # @param [Integer] start Zero-based index of the starting row to read.
        #
        # @return [Google::Cloud::Bigquery::Data] An object providing access to
        #   data read from the destination table for the job.
        #
        # @example
        #   require "google/cloud/bigquery"
        #
        #   bigquery = Google::Cloud::Bigquery.new
        #
        #   sql = "SELECT word FROM `bigquery-public-data.samples.shakespeare`"
        #   job = bigquery.query_job sql
        #
        #   job.wait_until_done!
        #   data = job.data
        #   data.each do |row|
        #     puts row[:word]
        #   end
        #   data = data.next if data.next?
        #
        def data token: nil, max: nil, start: nil
          return nil unless done?
          if dryrun?
            return Data.from_gapi_json({ rows: [] }, nil, @gapi, service)
          end
          if ddl? || dml?
            data_hash = { totalRows: nil, rows: [] }
            return Data.from_gapi_json data_hash, nil, @gapi, service
          end
          ensure_schema!

          options = { token: token, max: max, start: start }
          data_hash = service.list_tabledata \
            destination_table_dataset_id,
            destination_table_table_id,
            options
          Data.from_gapi_json data_hash, destination_table_gapi, @gapi, service
        end
        alias query_results data

        ##
        # Yielded to a block to accumulate changes for a patch request.
        class Updater < QueryJob
          ##
          # @private Create an Updater object.
          def initialize service, gapi
            @service = service
            @gapi = gapi
          end

          # rubocop:disable all

          ##
          # @private Create an Updater from an options hash.
          #
          # @return [Google::Cloud::Bigquery::QueryJob::Updater] A job
          #   configuration object for setting query options.
          def self.from_options service, query, options
            job_ref = service.job_ref_from options[:job_id], options[:prefix]
            dataset_config = service.dataset_ref_from options[:dataset],
                                                      options[:project]
            req = Google::Apis::BigqueryV2::Job.new(
              job_reference: job_ref,
              configuration: Google::Apis::BigqueryV2::JobConfiguration.new(
                query: Google::Apis::BigqueryV2::JobConfigurationQuery.new(
                  query: query,
                  default_dataset: dataset_config,
                  maximum_billing_tier: options[:maximum_billing_tier]
                )
              )
            )

            updater = QueryJob::Updater.new service, req
            updater.params = options[:params] if options[:params]
            updater.create = options[:create]
            updater.write = options[:write]
            updater.table = options[:table]
            updater.dryrun = options[:dryrun]
            updater.maximum_bytes_billed = options[:maximum_bytes_billed]
            updater.labels = options[:labels] if options[:labels]
            updater.legacy_sql = Convert.resolve_legacy_sql(
              options[:standard_sql], options[:legacy_sql])
            updater.external = options[:external] if options[:external]
            updater.priority = options[:priority]
            updater.cache = options[:cache]
            updater.large_results = options[:large_results]
            updater.flatten = options[:flatten]
            updater.udfs = options[:udfs]
            updater
          end

          # rubocop:enable all

          ##
          # Sets the geographic location where the job should run. Required
          # except for US and EU.
          #
          # @param [String] value  A geographic location, such as "US", "EU" or
          #   "asia-northeast1". Required except for US and EU.
          #
          # @example
          #   require "google/cloud/bigquery"
          #
          #   bigquery = Google::Cloud::Bigquery.new
          #   dataset = bigquery.dataset "my_dataset"
          #
          #   job = bigquery.query_job "SELECT 1;" do |query|
          #     query.table = dataset.table "my_table", skip_lookup: true
          #     query.location = "EU"
          #   end
          #
          # @!group Attributes
          def location= value
            @gapi.job_reference.location = value
            return unless value.nil?

            # Treat assigning value of nil the same as unsetting the value.
            unset = @gapi.job_reference.instance_variables.include? :@location
            @gapi.job_reference.remove_instance_variable :@location if unset
          end

          ##
          # Sets the priority of the query.
          #
          # @param [String] value Specifies a priority for the query. Possible
          #   values include `INTERACTIVE` and `BATCH`.
          #
          # @!group Attributes
          def priority= value
            @gapi.configuration.query.priority = priority_value value
          end

          ##
          # Specifies to look in the query cache for results.
          #
          # @param [Boolean] value Whether to look for the result in the query
          #   cache. The query cache is a best-effort cache that will be flushed
          #   whenever tables in the query are modified. The default value is
          #   true. For more information, see [query
          #   caching](https://developers.google.com/bigquery/querying-data).
          #
          # @!group Attributes
          def cache= value
            @gapi.configuration.query.use_query_cache = value
          end

          ##
          # Allow large results for a legacy SQL query.
          #
          # @param [Boolean] value This option is specific to Legacy SQL.
          #   If `true`, allows the query to produce arbitrarily large result
          #   tables at a slight cost in performance. Requires `table` parameter
          #   to be set.
          #
          # @!group Attributes
          def large_results= value
            @gapi.configuration.query.allow_large_results = value
          end

          ##
          # Flatten nested and repeated fields in legacy SQL queries.
          #
          # @param [Boolean] value This option is specific to Legacy SQL.
          #   Flattens all nested and repeated fields in the query results. The
          #   default value is `true`. `large_results` parameter must be `true`
          #   if this is set to `false`.
          #
          # @!group Attributes
          def flatten= value
            @gapi.configuration.query.flatten_results = value
          end

          ##
          # Sets the default dataset of tables referenced in the query.
          #
          # @param [Dataset] value The default dataset to use for unqualified
          #   table names in the query.
          #
          # @!group Attributes
          def dataset= value
            @gapi.configuration.query.default_dataset =
              @service.dataset_ref_from value
          end

          ##
          # Sets the query parameters. Standard SQL only.
          #
          # @param [Array, Hash] params Used to pass query arguments when the
          #   `query` string contains either positional (`?`) or named
          #   (`@myparam`) query parameters. If value passed is an array
          #   `["foo"]`, the query must use positional query parameters. If
          #   value passed is a hash `{ myparam: "foo" }`, the query must use
          #   named query parameters. When set, `legacy_sql` will automatically
          #   be set to false and `standard_sql` to true.
          #
          # @!group Attributes
          def params= params
            case params
            when Array then
              @gapi.configuration.query.use_legacy_sql = false
              @gapi.configuration.query.parameter_mode = "POSITIONAL"
              @gapi.configuration.query.query_parameters = params.map do |param|
                Convert.to_query_param param
              end
            when Hash then
              @gapi.configuration.query.use_legacy_sql = false
              @gapi.configuration.query.parameter_mode = "NAMED"
              @gapi.configuration.query.query_parameters =
                params.map do |name, param|
                  Convert.to_query_param(param).tap do |named_param|
                    named_param.name = String name
                  end
                end
            else
              raise "Query parameters must be an Array or a Hash."
            end
          end

          ##
          # Sets the create disposition for creating the query results table.
          #
          # @param [String] value Specifies whether the job is allowed to
          # create new tables. The default value is `needed`.
          #
          #   The following values are supported:
          #
          #   * `needed` - Create the table if it does not exist.
          #   * `never` - The table must already exist. A 'notFound' error is
          #     raised if the table does not exist.
          #
          # @!group Attributes
          def create= value
            @gapi.configuration.query.create_disposition =
              Convert.create_disposition value
          end

          ##
          # Sets the write disposition for when the query results table exists.
          #
          # @param [String] value Specifies the action that occurs if the
          #   destination table already exists. The default value is `empty`.
          #
          #   The following values are supported:
          #
          #   * `truncate` - BigQuery overwrites the table data.
          #   * `append` - BigQuery appends the data to the table.
          #   * `empty` - A 'duplicate' error is returned in the job result if
          #     the table exists and contains data.
          #
          # @!group Attributes
          def write= value
            @gapi.configuration.query.write_disposition =
              Convert.write_disposition value
          end

          ##
          # Sets the dry run flag for the query job.
          #
          # @param [Boolean] value If set, don't actually run this job. A valid
          #   query will return a mostly empty response with some processing
          #   statistics, while an invalid query will return the same error it
          #   would if it wasn't a dry run..
          #
          # @!group Attributes
          def dryrun= value
            @gapi.configuration.dry_run = value
          end
          alias dry_run= dryrun=

          ##
          # Sets the destination for the query results table.
          #
          # @param [Table] value The destination table where the query results
          #   should be stored. If not present, a new table will be created
          #   according to the create disposition to store the results.
          #
          # @!group Attributes
          def table= value
            @gapi.configuration.query.destination_table = table_ref_from value
          end

          ##
          # Sets the maximum bytes billed for the query.
          #
          # @param [Integer] value Limits the bytes billed for this job.
          #   Queries that will have bytes billed beyond this limit will fail
          #   (without incurring a charge). Optional. If unspecified, this will
          #   be set to your project default.
          #
          # @!group Attributes
          def maximum_bytes_billed= value
            @gapi.configuration.query.maximum_bytes_billed = value
          end

          ##
          # Sets the labels to use for the job.
          #
          # @param [Hash] value A hash of user-provided labels associated with
          #   the job. You can use these to organize and group your jobs. Label
          #   keys and values can be no longer than 63 characters, can only
          #   contain lowercase letters, numeric characters, underscores and
          #   dashes. International characters are allowed. Label values are
          #   optional. Label keys must start with a letter and each label in
          #   the list must have a different key.
          #
          # @!group Attributes
          #
          def labels= value
            @gapi.configuration.update! labels: value
          end

          ##
          # Sets the query syntax to legacy SQL.
          #
          # @param [Boolean] value Specifies whether to use BigQuery's [legacy
          #   SQL](https://cloud.google.com/bigquery/docs/reference/legacy-sql)
          #   dialect for this query. If set to false, the query will use
          #   BigQuery's [standard
          #   SQL](https://cloud.google.com/bigquery/docs/reference/standard-sql/)
          #   dialect. Optional. The default value is false.
          #
          # @!group Attributes
          #
          def legacy_sql= value
            @gapi.configuration.query.use_legacy_sql = value
          end

          ##
          # Sets the query syntax to standard SQL.
          #
          # @param [Boolean] value Specifies whether to use BigQuery's [standard
          #   SQL](https://cloud.google.com/bigquery/docs/reference/standard-sql/)
          #   dialect for this query. If set to true, the query will use
          #   standard SQL rather than the [legacy
          #   SQL](https://cloud.google.com/bigquery/docs/reference/legacy-sql)
          #   dialect. Optional. The default value is true.
          #
          # @!group Attributes
          #
          def standard_sql= value
            @gapi.configuration.query.use_legacy_sql = !value
          end

          ##
          # Sets definitions for external tables used in the query.
          #
          # @param [Hash<String|Symbol, External::DataSource>] value A Hash
          #   that represents the mapping of the external tables to the table
          #   names used in the SQL query. The hash keys are the table names,
          #   and the hash values are the external table objects.
          #
          # @!group Attributes
          #
          def external= value
            external_table_pairs = value.map do |name, obj|
              [String(name), obj.to_gapi]
            end
            external_table_hash = Hash[external_table_pairs]
            @gapi.configuration.query.table_definitions = external_table_hash
          end

          ##
          # Sets user defined functions for the query.
          #
          # @param [Array<String>, String] value User-defined function resources
          #   used in the query. May be either a code resource to load from a
          #   Google Cloud Storage URI (`gs://bucket/path`), or an inline
          #   resource that contains code for a user-defined function (UDF).
          #   Providing an inline code resource is equivalent to providing a URI
          #   for a file containing the same code. See [User-Defined
          #   Functions](https://cloud.google.com/bigquery/docs/reference/standard-sql/user-defined-functions).
          #
          # @!group Attributes
          def udfs= value
            @gapi.configuration.query.user_defined_function_resources =
              udfs_gapi_from value
          end

          ##
          # Sets the encryption configuration of the destination table.
          #
          # @param [Google::Cloud::BigQuery::EncryptionConfiguration] val
          #   Custom encryption configuration (e.g., Cloud KMS keys).
          #
          # @example
          #   require "google/cloud/bigquery"
          #
          #   bigquery = Google::Cloud::Bigquery.new
          #   dataset = bigquery.dataset "my_dataset"
          #
          #   key_name = "projects/a/locations/b/keyRings/c/cryptoKeys/d"
          #   encrypt_config = bigquery.encryption kms_key: key_name
          #   job = bigquery.query_job "SELECT 1;" do |job|
          #     job.table = dataset.table "my_table", skip_lookup: true
          #     job.encryption = encrypt_config
          #   end
          #
          # @!group Attributes
          def encryption= val
            @gapi.configuration.query.update!(
              destination_encryption_configuration: val.to_gapi
            )
          end

          ##
          # Sets the partitioning for the destination table. See [Partitioned
          # Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
          #
          # You can only set the partitioning field while creating a table.
          # BigQuery does not allow you to change partitioning on an existing
          # table.
          #
          # @param [String] type The partition type. Currently the only
          #   supported value is "DAY".
          #
          # @example
          #   require "google/cloud/bigquery"
          #
          #   bigquery = Google::Cloud::Bigquery.new
          #   dataset = bigquery.dataset "my_dataset"
          #   destination_table = dataset.table "my_destination_table",
          #                                     skip_lookup: true
          #
          #   job = dataset.query_job "SELECT * FROM UNNEST(" \
          #                           "GENERATE_TIMESTAMP_ARRAY(" \
          #                           "'2018-10-01 00:00:00', " \
          #                           "'2018-10-10 00:00:00', " \
          #                           "INTERVAL 1 DAY)) AS dob" do |job|
          #     job.table = destination_table
          #     job.time_partitioning_type = "DAY"
          #   end
          #
          #   job.wait_until_done!
          #   job.done? #=> true
          #
          # @!group Attributes
          #
          def time_partitioning_type= type
            @gapi.configuration.query.time_partitioning ||= \
              Google::Apis::BigqueryV2::TimePartitioning.new
            @gapi.configuration.query.time_partitioning.update! type: type
          end

          ##
          # Sets the field on which to partition the destination table. If not
          # set, the destination table is partitioned by pseudo column
          # `_PARTITIONTIME`; if set, the table is partitioned by this field.
          # See [Partitioned
          # Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
          #
          # The destination table must also be partitioned. See
          # {#time_partitioning_type=}.
          #
          # You can only set the partitioning field while creating a table.
          # BigQuery does not allow you to change partitioning on an existing
          # table.
          #
          # @param [String] field The partition field. The field must be a
          #   top-level TIMESTAMP or DATE field. Its mode must be NULLABLE or
          #   REQUIRED.
          #
          # @example
          #   require "google/cloud/bigquery"
          #
          #   bigquery = Google::Cloud::Bigquery.new
          #   dataset = bigquery.dataset "my_dataset"
          #   destination_table = dataset.table "my_destination_table",
          #                                     skip_lookup: true
          #
          #   job = dataset.query_job "SELECT * FROM UNNEST(" \
          #                           "GENERATE_TIMESTAMP_ARRAY(" \
          #                           "'2018-10-01 00:00:00', " \
          #                           "'2018-10-10 00:00:00', " \
          #                           "INTERVAL 1 DAY)) AS dob" do |job|
          #     job.table = destination_table
          #     job.time_partitioning_type  = "DAY"
          #     job.time_partitioning_field = "dob"
          #   end
          #
          #   job.wait_until_done!
          #   job.done? #=> true
          #
          # @!group Attributes
          #
          def time_partitioning_field= field
            @gapi.configuration.query.time_partitioning ||= \
              Google::Apis::BigqueryV2::TimePartitioning.new
            @gapi.configuration.query.time_partitioning.update! field: field
          end

          ##
          # Sets the partition expiration for the destination table. See
          # [Partitioned
          # Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
          #
          # The destination table must also be partitioned. See
          # {#time_partitioning_type=}.
          #
          # @param [Integer] expiration An expiration time, in seconds,
          #   for data in partitions.
          #
          # @example
          #   require "google/cloud/bigquery"
          #
          #   bigquery = Google::Cloud::Bigquery.new
          #   dataset = bigquery.dataset "my_dataset"
          #   destination_table = dataset.table "my_destination_table",
          #                                     skip_lookup: true
          #
          #   job = dataset.query_job "SELECT * FROM UNNEST(" \
          #                           "GENERATE_TIMESTAMP_ARRAY(" \
          #                           "'2018-10-01 00:00:00', " \
          #                           "'2018-10-10 00:00:00', " \
          #                           "INTERVAL 1 DAY)) AS dob" do |job|
          #     job.table = destination_table
          #     job.time_partitioning_type = "DAY"
          #     job.time_partitioning_expiration = 86_400
          #   end
          #
          #   job.wait_until_done!
          #   job.done? #=> true
          #
          # @!group Attributes
          #
          def time_partitioning_expiration= expiration
            @gapi.configuration.query.time_partitioning ||= \
              Google::Apis::BigqueryV2::TimePartitioning.new
            @gapi.configuration.query.time_partitioning.update! \
              expiration_ms: expiration * 1000
          end

          ##
          # If set to true, queries over the destination table will require a
          # partition filter that can be used for partition elimination to be
          # specified. See [Partitioned
          # Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
          #
          # @param [Boolean] val Indicates if queries over the destination table
          #   will require a partition filter. The default value is `false`.
          #
          # @!group Attributes
          #
          def time_partitioning_require_filter= val
            @gapi.configuration.query.time_partitioning ||= \
              Google::Apis::BigqueryV2::TimePartitioning.new
            @gapi.configuration.query.time_partitioning.update! \
              require_partition_filter: val
          end

          ##
          # Sets one or more fields on which the destination table should be
          # clustered. Must be specified with time-based partitioning, data in
          # the table will be first partitioned and subsequently clustered.
          #
          # Only top-level, non-repeated, simple-type fields are supported. When
          # you cluster a table using multiple columns, the order of columns you
          # specify is important. The order of the specified columns determines
          # the sort order of the data.
          #
          # See {QueryJob#clustering_fields}.
          #
          # @see https://cloud.google.com/bigquery/docs/partitioned-tables
          #   Partitioned Tables
          # @see https://cloud.google.com/bigquery/docs/clustered-tables
          #   Introduction to Clustered Tables
          # @see https://cloud.google.com/bigquery/docs/creating-clustered-tables
          #   Creating and Using Clustered Tables
          #
          # @param [Array<String>] fields The clustering fields. Only top-level,
          #   non-repeated, simple-type fields are supported.
          #
          # @example
          #   require "google/cloud/bigquery"
          #
          #   bigquery = Google::Cloud::Bigquery.new
          #   dataset = bigquery.dataset "my_dataset"
          #   destination_table = dataset.table "my_destination_table",
          #                                     skip_lookup: true
          #
          #   job = dataset.query_job "SELECT * FROM my_table" do |job|
          #     job.table = destination_table
          #     job.time_partitioning_type = "DAY"
          #     job.time_partitioning_field = "dob"
          #     job.clustering_fields = ["last_name", "first_name"]
          #   end
          #
          #   job.wait_until_done!
          #   job.done? #=> true
          #
          # @!group Attributes
          #
          def clustering_fields= fields
            @gapi.configuration.query.clustering ||= \
              Google::Apis::BigqueryV2::Clustering.new
            @gapi.configuration.query.clustering.fields = fields
          end

          ##
          # @private Returns the Google API client library version of this job.
          #
          # @return [<Google::Apis::BigqueryV2::Job>] (See
          #   {Google::Apis::BigqueryV2::Job})
          def to_gapi
            @gapi
          end

          protected

          # Creates a table reference from a table object.
          def table_ref_from tbl
            return nil if tbl.nil?
            Google::Apis::BigqueryV2::TableReference.new(
              project_id: tbl.project_id,
              dataset_id: tbl.dataset_id,
              table_id:   tbl.table_id
            )
          end

          def priority_value str
            { "batch"       => "BATCH",
              "interactive" => "INTERACTIVE" }[str.to_s.downcase]
          end

          def udfs_gapi_from array_or_str
            Array(array_or_str).map do |uri_or_code|
              resource =
                Google::Apis::BigqueryV2::UserDefinedFunctionResource.new
              if uri_or_code.start_with? "gs://"
                resource.resource_uri = uri_or_code
              else
                resource.inline_code = uri_or_code
              end
              resource
            end
          end
        end

        ##
        # Represents a stage in the execution plan for the query.
        #
        # @attr_reader [Float] compute_ratio_avg Relative amount of time the
        #   average shard spent on CPU-bound tasks.
        # @attr_reader [Float] compute_ratio_max Relative amount of time the
        #   slowest shard spent on CPU-bound tasks.
        # @attr_reader [Integer] id Unique ID for the stage within the query
        #   plan.
        # @attr_reader [String] name Human-readable name for the stage.
        # @attr_reader [Float] read_ratio_avg Relative amount of time the
        #   average shard spent reading input.
        # @attr_reader [Float] read_ratio_max Relative amount of time the
        #   slowest shard spent reading input.
        # @attr_reader [Integer] records_read Number of records read into the
        #   stage.
        # @attr_reader [Integer] records_written Number of records written by
        #   the stage.
        # @attr_reader [Array<Step>] steps List of operations within the stage
        #   in dependency order (approximately chronological).
        # @attr_reader [Float] wait_ratio_avg Relative amount of time the
        #   average shard spent waiting to be scheduled.
        # @attr_reader [Float] wait_ratio_max Relative amount of time the
        #   slowest shard spent waiting to be scheduled.
        # @attr_reader [Float] write_ratio_avg Relative amount of time the
        #   average shard spent on writing output.
        # @attr_reader [Float] write_ratio_max Relative amount of time the
        #   slowest shard spent on writing output.
        #
        # @example
        #   require "google/cloud/bigquery"
        #
        #   bigquery = Google::Cloud::Bigquery.new
        #
        #   sql = "SELECT word FROM `bigquery-public-data.samples.shakespeare`"
        #   job = bigquery.query_job sql
        #
        #   job.wait_until_done!
        #
        #   stages = job.query_plan
        #   stages.each do |stage|
        #     puts stage.name
        #     stage.steps.each do |step|
        #       puts step.kind
        #       puts step.substeps.inspect
        #     end
        #   end
        #
        class Stage
          attr_reader :compute_ratio_avg, :compute_ratio_max, :id, :name,
                      :read_ratio_avg, :read_ratio_max, :records_read,
                      :records_written, :status, :steps, :wait_ratio_avg,
                      :wait_ratio_max, :write_ratio_avg, :write_ratio_max

          ##
          # @private Creates a new Stage instance.
          def initialize compute_ratio_avg, compute_ratio_max, id, name,
                         read_ratio_avg, read_ratio_max, records_read,
                         records_written, status, steps, wait_ratio_avg,
                         wait_ratio_max, write_ratio_avg, write_ratio_max
            @compute_ratio_avg = compute_ratio_avg
            @compute_ratio_max = compute_ratio_max
            @id                = id
            @name              = name
            @read_ratio_avg    = read_ratio_avg
            @read_ratio_max    = read_ratio_max
            @records_read      = records_read
            @records_written   = records_written
            @status            = status
            @steps             = steps
            @wait_ratio_avg    = wait_ratio_avg
            @wait_ratio_max    = wait_ratio_max
            @write_ratio_avg   = write_ratio_avg
            @write_ratio_max   = write_ratio_max
          end

          ##
          # @private New Stage from a statistics.query.queryPlan element.
          def self.from_gapi gapi
            steps = Array(gapi.steps).map { |g| Step.from_gapi g }
            new gapi.compute_ratio_avg, gapi.compute_ratio_max, gapi.id,
                gapi.name, gapi.read_ratio_avg, gapi.read_ratio_max,
                gapi.records_read, gapi.records_written, gapi.status, steps,
                gapi.wait_ratio_avg, gapi.wait_ratio_max, gapi.write_ratio_avg,
                gapi.write_ratio_max
          end
        end

        ##
        # Represents an operation in a stage in the execution plan for the
        # query.
        #
        # @attr_reader [String] kind Machine-readable operation type. For a full
        #   list of operation types, see [Steps
        #   metadata](https://cloud.google.com/bigquery/query-plan-explanation#steps_metadata).
        # @attr_reader [Array<String>] substeps Human-readable stage
        #   descriptions.
        #
        # @example
        #   require "google/cloud/bigquery"
        #
        #   bigquery = Google::Cloud::Bigquery.new
        #
        #   sql = "SELECT word FROM `bigquery-public-data.samples.shakespeare`"
        #   job = bigquery.query_job sql
        #
        #   job.wait_until_done!
        #
        #   stages = job.query_plan
        #   stages.each do |stage|
        #     puts stage.name
        #     stage.steps.each do |step|
        #       puts step.kind
        #       puts step.substeps.inspect
        #     end
        #   end
        #
        class Step
          attr_reader :kind, :substeps

          ##
          # @private Creates a new Stage instance.
          def initialize kind, substeps
            @kind = kind
            @substeps = substeps
          end

          ##
          # @private New Step from a statistics.query.queryPlan[].steps element.
          def self.from_gapi gapi
            new gapi.kind, Array(gapi.substeps)
          end
        end

        protected

        def ensure_schema!
          return unless destination_schema.nil?

          query_results_gapi = service.job_query_results \
            job_id, location: location, max: 0
          # raise "unable to retrieve schema" if query_results_gapi.schema.nil?
          @destination_schema_gapi = query_results_gapi.schema
        end

        def destination_schema
          @destination_schema_gapi
        end

        def destination_table_dataset_id
          @gapi.configuration.query.destination_table.dataset_id
        end

        def destination_table_table_id
          @gapi.configuration.query.destination_table.table_id
        end

        def destination_table_gapi
          Google::Apis::BigqueryV2::Table.new \
            table_reference: @gapi.configuration.query.destination_table,
            schema:          destination_schema
        end
      end
    end
  end
end

redpajama_set_name: RedPajamaGithub


Mohawk Hair Styles – When it comes to Mohawk Hair Styles, many people fall into one of 2 classes. The I know exactly how I want my hair to look crew, or the OMFG what am I going to do with my own hair squad. And you know, I should be perfect at this. As a hairstylist who works weddings, I have spent hundreds of hours around brides performing hair. But somehow I found myself actually cutting my hair in the bathroom in my wedding day. Yeah, true story.
So in the interest of not being like me (seriously, don't attempt this at home ), we are here to help save you some frustration by walking through how to discover the very best Mohawk Hair Styles for you (and your own hair!) , and how to locate a stylist to make that happen. If you're considering moving the DIY hair path, we got you too check our articles here and here.
Trying to figure out which Mohawk Hair Styles will work best for you can originally be a little tricky. As we know, Pinterest and also the Interwebs are chock full of gorgeous images, but a lot of those are of hair models sporting loads of extensions, together with a stylist, killer light, and a buff. When you find any images you prefer ask yourself this, does this look like my hair can do what's in that film? On your wedding day, you should aim to seem like a slightly fancier version of your self. Don't make this the day you're trying out some totally new style for your very first time.
Girls Braid Hairstyle Elegant Ely Pics Braids Hairstyles Lovely Braided Mohawk Hairstyles 0d. Source image : fezfestival.org.
Mohawk Hairstyle for Girl Lovely Braids Hairstyles Luxury Braided Mohawk Hairstyles 0d Braids. Source image : fezfestival.org.
Mohawk Hairstyles Girls Beautiful Mohawk Hair Style New Black Hairstyles Mohawks Elegant Braided Mohawk Hairstyles. Source image : fezfestival.org.
Extravagant Lovely Mens Mohawk Haircut Beehive Hair Cutting Recon Haircut 0d By 2018 Mohawk Hairstyles For Men. Source image : pccheatz.com.
Mohawk Hairstyle For Girl Beautiful Hair Style Braids Graph Braids Hairstyles Luxury Braided Mohawk. Source image : fezfestival.org.
Hair and Beauty Mohawk Hairstyles for Men Amusing Hairstyle New Hairstyle Beautiful New Hair Cut and Color 0d. Source image : ayitihistory.com.
Lovely Black Hair Styles Braids Elegant I Pinimg originals F4 7d 0d F47d0df3d03d Black Men Braid. Source image : treatinfectionsonline.com.
We've written at length about ways to make Mohawk Hair Styles. But the short version is this beginning by checking our Vendor Directory, talk to your own stylist, or ask friends for a referral. Most stylists require a trial so as to reserve your marriage. While initially this may totally look like one of these moments and like something you do not need, it absolutely is a must. That can be as much for you as it's for the stylist. Once it gives them an opportunity get a sense of your own hair, it gives you a opportunity to get to know somebody who will be with you in a potentially stressful time. You want someone who you feel comfortable with, and are going to be able to stay calm and professional.
At your trial, bring your stylist several choices of things you like, and consider why you enjoy those looks. Is it the curls, the colors, the accessories? Remember that the neckline of your dress and any jewelry you anticipate wearing, along with veil or other headpieces. Even the best stylists can not replicate a fashion just: the hair isn't the same as the person in the picture. Your stylist will make a style that works for you and your hair, which in the long run is going to be a far more successful fashion than a bad copy of Pinterest.
To help you in your search for Mohawk Hair Styles that are going to work for you, today we've rounded up my favourite hairstyles for short, medium to long, and curled hair, for all kinds of textures and thicknesses. If you're searching for even more specific hair types, take a look at our favorite Mohawk Hair Styles for dark hair, specific hairstyles, short hair, and curly hair.
Short doesn't mean dull, not for one moment. When it can feel like it'll be tough to make it feel different from your daily hair, keep in mind you are going to be spiffed up sporting a killer ensemble –that is not a standard day. Pro tip: Adding an accessory is the best-kept key in hair. It aids the style feel elevated and completed. Or go with a bold eye or lip to bring your look up several notches. Check out our post on Mohawk Hair Styles accessories for your hair.


text:
Justification in the air amid Man City's historic treble
By Joe Prince-WrightMay 18, 2019, 3:44 PM EDT
LONDON — Until their name is cleared by UEFA, questions will remain about Manchester City's incredible domestic treble. Justification was in the air at Wembley on Saturday.
[ MORE: Man City win FA Cup ]
Moments after hammering Watford to win the FA Cup to complete something no other men's team in English history had achieved, Pep Guardiola was asked questions, rightly so, about City's achievements on the pitch being diminished by ongoing investigations off the pitch.
It is something you just can't ignore.
At the final whistle at Wembley, a Man City fan somehow burst into the press seating area and as he was being escorted away by security he accused the media of ignoring Man City winning the domestic treble, saying that "Mo Salah will be on the back pages" tomorrow. That exchanged summed up the feeling of a large portion of Man City fans right now. Just check their responses on social media.
City are a club in full justification mood as they celebrate the most glorious season in their history.
With UEFA opening up another investigation into allegations of City deliberately circumventing financial fair flay (FFP) rules, a decision on what punishment they will receive is imminent after UEFA's Club Financial Control Body (CFCB) has referred City to the CFCB adjudicatory chamber.
A minimum one-year ban from the Champions League has been reportedly recommended, and Guardiola is ready for any punishment coming their way.
"We are not guilty until proven," Guardiola said. "When I say this squad make the first step forward with Sheikh Mansour, definitely. You can't do that without top players. No way. Money helps to buy the incredible players we have. After that, we wait. If we are punished we will accept it. But I listen to my chairman and listen to my CEO and they give me the arguments why they are under investigation, and I trust them. When they tell me that we absolutely followed the rules, I believe them. If the opponent and contenders believe just money does that, it is okay."
Guardiola was then asked about allegations that Roberto Mancini received separate payments from Abu Dhabi while he was in charge of Man City, and if he himself had ever been involved in similar payments, something he hadn't answered previously when asked.
City's boss wasn't a fan of being asked that question minutes after completing the League Cup, Premier League and FA Cup treble.
"Do you know the question you are asking to me? Do you know the question you are asking me? If I received money from another situation right now, today. Honestly," Guardiola fumed. "Do you think I deserve to have this type of question, what happened with Roberto I don't know, the day I win the treble about if I received money in other situations…"
These questions will go on and City will continue to see their amazing victories, performances and trophies won on the pitch undermined until they are proven once and for all not guilty of the allegations brought about by the investigations brought up again after more details were released via Football Leaks.
Their fans feel like the achievements of their team aren't lauded enough by the media, and the strong statements of the club against UEFA have put up a fence between themselves and the rest of the soccer world.
Guardiola's achievement of winning the treble this season should not go without huge praise. Finances aside, he has created a remarkable team which is capable of ripping up the record books once again next season.
The Spanish coach admitted that this season wasn't his best as a manager (that title will surely go to the 2008-09 campaign when he won the treble, including the Champions League, at Barcelona), but did take a shot at Liverpool and Tottenham reaching the Champions League final in Madrid on June 1, as City were denied a chance to win an even more historic quadruple.
"I wouldn't say the best, but one of the best, sure," Guardiola said. "In 10 months, to play in all competitions, and the fact that none of the other incredible teams have done this in this country, to be the first means that if one team is able to do that, another team is going to be able to repeat. We were the first and it means to be consistent every three days. I love the Champions League, but to do this is more difficult than winning the Champions League. We did it."
Pep is following City's fans and officials in feeling the need to add extra justification to their historic season.
Follow @JPW_NBCSports
Tags: FA Cup, Manchester City, Pep Guardiola, Premier League, Pep Guardiola
USMNT's Boyd signs with Besiktas
By Daniel KarellJul 15, 2019, 4:11 PM EDT
Add another American to the list of players who will be playing in UEFA competitions this fall.
Turkish giant Besiktas announced on Monday that it had signed winger Tyler Boyd to a four-year contract in a transfer from Portuguese side Vitoria Guimaraes. Boyd has had a pretty impressive last six months, from scoring six goals in 14 games with Ankaragücü in the Turkish Superlig on loan, to scoring goals and making the Gold Cup roster for the U.S. Men's National Team.
[READ: Transfer Rumor Roundup]
Beşiktaşımıza Hoş Geldin Tyler Boyd 🦅 Welcome to Beşiktaş @Tyler__Boyd 💪 pic.twitter.com/zxCdpPE1aS
— Beşiktaş JK (@Besiktas) July 15, 2019
The New Zealand-born pacey winger completed a one-time switch to play for the USMNT in May, and he went on to score a brace in the USMNT's Gold Cup opener against Guyana. While Boyd made five appearances for the U.S. this summer, he was left on the bench as the U.S. bowed out to Mexico, suddenly appearing out of Berhalter's plans as quickly as he entered them.
Regardless, this is a great move for Boyd, assuming he can get some first team minutes. It's a big step up from Ankaragücü to play for Besiktas, which not only includes the heated Istanbul derbies against Fenerbahce and Galatasaray, but next season will also include at least six matches in the UEFA Europa League. By finishing third in the Turkish league, Besiktas earned a place direct in the Europa League group stage.
Of course, like we saw this summer with the USMNT, Boyd has to break into a more talented group of players and earn minutes, both for league and European matches. If he's not playing much, it's possible we won't see much of him with the national team, as Jordan Morris gets regular playing time as well as others in that position like Timothy Weah, Corey Baird and possibly Kenny Saief, now that he's back with Anderlecht.
Boyd is undoubtedly a talented player. Hopefully, this move up in stature and pressure can help the 24-year-old take his game to a new level.
Tags: Besiktas, Tyler Boyd, USMNT, Ba
USMNT's Boyd signs with Besiktas July 15, 2019 4:11 pm Report: Manchester United "miles" apart on Maguire deal July 15, 2019 2:08 pm Transfer Rumor Roundup: James to Atletico, Rondon to China July 15, 2019 12:29 pm Ajax exec Overmars makes Ziyech sales pitch to Arsenal July 15, 2019 12:12 pm Chelsea signs youth product Mason Mount to new contract July 15, 2019 10:29 am Steve Bruce resigns Sheffield Wednesday post with Newcastle move imminent July 15, 2019 9:40 am Iker Casillas handed liaison role at Porto during recovery July 15, 2019 8:00 am PL friendly roundup: Liverpool win; Everton, Saints, Norwich draw July 14, 2019 10:44 pm RBNY come back to beat NYCFC on bizarre call by refs (video) July 14, 2019 8:52 pm Griezmann thankful for 'another chance' to join Barcelona July 14, 2019 8:04 pm VIDEO: Mahrez sends Algeria to AFCON final with game's last kick July 14, 2019 6:35 pm Sounders beat Atlanta on goals from Ruidiaz, Shipp (video) July 14, 2019 6:05 pm FOLLOW LIVE, MLS Sunday: Seattle v. Atlanta, Red Bulls v. NYCFC July 14, 2019 4:00 pm Wacky extra time own-goal sends Senegal into Africa Cup of Nations final July 14, 2019 2:56 pm Transfer Rumor Roundup: Dunk to Leicester City, Everton to Arsenal July 14, 2019 1:34 pm Report: Marseille suspends Rami for lying about attending game show July 14, 2019 12:30 pm FOLLOW LIVE – AFCON semifinals features two enticing matchups July 14, 2019 11:55 am MLS Saturday Wrap: What we learned July 14, 2019 11:25 am Valencia signs Celta Vigo striker Maxi Gomez July 14, 2019 10:48 am Reports: Manchester United agree to world record Harry Maguire deal July 14, 2019 9:50 am Pulisic impressing Lampard with early preseason start July 14, 2019 8:24 am Should Chelsea risk not selling Hudson-Odoi? July 13, 2019 11:14 pm Reports: Arsenal to spend big for Pepe, Tierney July 13, 2019 9:49 pm USMNT's Novakovich scores in Reading friendly July 13, 2019 7:52 pm Premier League Friendly Roundup: Chelsea, Man United win July 13, 2019 7:29 pm Albania club says UEFA 10-year ban on fixing is "prejudiced" July 13, 2019 7:05 pm Report: Discussions being held between Newcastle and Bruce July 13, 2019 5:38 pm Dier to miss Spurs Asia tour July 13, 2019 3:55 pm Napoli, loading up to dethrone Juve, sign defensive rock Manolas July 13, 2019 2:05 pm Bologna manager Mihajlovic announces he has leukemia July 13, 2019 12:30 pm Pogba refuses to discuss transfer rumors: 'There is no need to talk' July 13, 2019 11:47 am Pogba sets up Rashford in Man United's win in Australia July 13, 2019 11:05 am Transfer rumor roundup: Bayern Munich chasing Sane, Dembele July 13, 2019 9:46 am Matthijs de Ligt left off Ajax roster for start of preseason July 13, 2019 8:38 am Quakes dominate Galaxy to sweep Cali Clasico in 2019 (video) July 13, 2019 1:12 am LAFC erases an early deficit, cruises to win in Houston (video) July 12, 2019 11:34 pm Arena's Revs blow two-goal lead, split points with DCU (video) July 12, 2019 9:12 pm FOLLOW LIVE: Three key conference clashes in MLS on Friday July 12, 2019 6:40 pm Newcastle quoted new, "far greater" price to hire Steve Bruce July 12, 2019 6:13 pm American winger Haji Wright signs with Eredivisie's Venlo July 12, 2019 4:47 pm

redpajama_set_name: RedPajamaCommonCrawl


text:
Il palazzo Marcantonio Sauli è un edificio sito in via San Bernardo al civico 19 nel centro storico di Genova. L'edificio fu inserito nella lista dei palazzi iscritti ai Rolli di Genova.

Storia e descrizione
Marcantonio Sauli (1523-1618), religioso e diplomatico, lo costruisce nella seconda metà del XVI secolo su preesistenze medievali degli Zaccaria: una famiglia di grande ruolo nel mediterraneo medievale, in cui spicca esemplare la vita avventurosa e cosmopolita di Benedetto Soprani, nella lunga narrazione della vita di Marcantonio, cui dedica il libro, afferma che nel palazzo "fu trovata l'insigne reliquia della Vera Croce", cioè della croce bizantina portata dagli Zaccaria a Genova, oggi custodita nel Museo del tesoro della cattedrale di San Lorenzo, con cui si benediceva il doge dopo l'elezione.

Presente nei rolli dal 1588 raggiunge la prima categoria nel 1614, a nome di Paolo Sauli, nipote di Marcantonio e senatore della Repubblica di Genova.

La rifusione di lotti medievali attorno al cortile ha dato origine a un palazzo notevole nelle dimensioni, anche se privo di uniformità nell'insieme. La soluzione è lontana dalle audacie architettoniche di Strada Nuova, ma la successione cinquecentesca atrio-cortile-scala si appoggia a un tessuto ancora rado e alla capacità tecnica di maestranze che individuano nella scala e nel cortile, poi abbellito con una statua di Venere anfitrite, soluzioni originali di collegamento orizzontale e verticale.

Tracce medievali (XIII secolo) sono ancora presenti in facciata: i conci in pietra nera e marmo, gli archetti ogivali pensili, le polifore tamponate al primo piano, l'arco a sesto ribassato oltre alla bifora gotica in marmo bianco al piano terra.

A partire dal XVIII secolo il palazzo, di proprietà Scaglia, viene locato a membri di famiglie nobili tra cui Giovanni Battista Negrone (doge nel 1769-1771) ma anche a intellettuali come Oderico e il dottor Mongiardini, primo teorico dell'ospedale antimiasmiatico.

A fine secolo, con la nuova proprietà degli armatori Schiaffino di Camogli, diviene sede del Tribunale di commercio. Poi, l'uso a magazzino dà avvio al degrado.

Voci correlate
 Rolli di Genova

Altri progetti

Collegamenti esterni

Sauli Marcantonio

redpajama_set_name: RedPajamaWikipedia


text:
Eldridge Announces Staff Hires
Posted on 03/26/2009 03/26/2009 by Team Eldridge
Senator Jamie Eldridge (D-Acton) has announced his State Senate staff, including Neel Chaudhury as Chief of Staff, Sally Schnitzer as Legislative Director, Melissa Threadgill as Communications Director, Brendan Jarboe as Legislative Aide, Peggy Ayers as District Director, and Beata Bujalska as Office Manager.
"I've brought together a talented, well-seasoned group of people to form my Senate staff. They come from varied backgrounds and bring a broad range of experience — and all of them are dedicated to serving the people of the Middlesex & Worcester District to the best of their abilities," noted Senator Eldridge. "I was particularly pleased to have been able to keep two staff members – Sally and Peggy – from Senator Resor's staff, to provide as much continuity and familiarity with the district as possible."
Chief of Staff Neel Chaudhury comes from Senator Eldridge's House staff, where he served as Legislative Aide. A native of Brookline, Chaudhury earned a degree in Economics at Boston University. He brings experience from both the public and private sector; before joining Eldridge's staff, Chaudhury worked in US Fixed Income Securities Finance at State Street Bank and Trust. Chaudhury also served as the Field Director for Eldridge's 2007 Congressional Campaign, and spent time working in U.S. Representative Barney Frank's office in Washington, D. C. Chaudhury has the distinction of being the first Indian-American to serve as a Chief of Staff in the Senate.
Sally Schnitzer, Legislative Director, is a graduate of Wellesley College and the University of Wisconsin, with degrees in geology and water resources management. She has worked for and served on the boards of several regional environmental organizations. A resident of the Town of Concord, she is a former member and former chairman of the town's conservation commission, planning board, public works commission, and Board of Selectmen. Sally was Legislative Director for former State Senator Pamela Resor from 2005 to 2008.
Melissa Threadgill joins the staff as Communications Director. Most recently, Threadgill served as Communications Director for MassEquality, a statewide advocacy organization working for LGBT equality, including equal marriage rights. Before coming to MassEquality, Melissa was an Account Executive at Bishoff Communications, a Boston-based public relations firm. Threadgill is also a veteran of numerous political campaigns, including Sonia Chang-Diaz's campaign for State Senate and Maura Hennigan's 2005 campaign for Mayor of Boston. Threadgill earned a Bachelor's degree in Politics at Oberlin College.
Brendan Jarboe will be serving as Senator Eldridge's Legislative Aide. Mr. Jarboe, a native of Acton, graduated from Bates College in Lewiston, Maine in May of 2008 with a degree in History. Prior to working at the Statehouse Mr. Jarboe served as the Field Director for Senator Eldridge's campaign.
District Director Peggy Ayers will be running Senator Eldridge's district office in Marlborough, where she resides. Prior to joining Eldridge's staff, she served Senator Pam Resor as District Director for ten years. A mother of six children (with three grandchildren), Ayers has been very active in the community, including Chair of the Mayor's Youth Commission, Chair of the City of Marlborough Recycling Committee, and a Board Member of MassRecycle. In 2008, she was named Humanitarian of the Year by Marlborough Mayor Nancy Stevens. Ayers is a graduate of Framingham State College.
Beata Bujalska, Office Manager, is a graduate student in Philosophy at Tufts University. Most recently, she's interned with Mass Alliance and at the Laborer's International Union of North American in their Strategic Communications Department.
This entry was posted in Press Releases. Bookmark the permalink.
← It's Official: Senator Jamie Eldridge Sworn Into Office
Local Aid Reduced in Latest Budget Cuts →


text:
Home Technology Security Matters Exhibits Strong Progress in Commercialisation of Disruptive technology
Security Matters Exhibits Strong Progress in Commercialisation of Disruptive technology
Security Matters Limited (ASX: SMX) is primarily involved in providing brand protection and supply chain integrity solutions to the businesses. Its patented unique technology utilizes a hidden barcode (chemical-based) to permanently 'mark' any object (solid/gas/liquid). The barcode is read using the company's unique 'reader' to access the equivalent stored data, recorded and protected using blockchain technology. In an era of the digital economy, SMX is trying to maintain trust in the physical assets and processes, by allowing identification, quality assurance and tracking supply chain movements.
The company was listed on ASX in late 2018 and within less than a year, the stock has provided a return of around 112.2% to its investors. This is a testament that the investors have a positive outlook about this brand protection, supply chain integrity and blockchain technology-based company with a strong belief in its disruptive technology. The company recently raised $6 million before costs by completing an oversubscribed share placement (12.4 million ordinary shares issued at $0.50 per share). The placement was completed 2.5 times the IPO price further demonstrating strong growth and support from the market.
In the recent past, the company developed various commercially meaningful relationships with several international organisations. The company has been partnering with global leading players across several sectors to protect brands, sectors and becoming the global record of physical goods.
Recently, SMX signed an agreement to commence a feasibility study with world-leading animal nutrition firm, Bluestar Adisseo Company. Under this agreement, both the companies will commence a pilot project to evaluate how Security Matters' disruptive technology can be incorporated into Adisseo's animal feed additives, to protect the Adisseo brand, secure the integrity of the industry and allow good incorporation into the feed.
Furthermore, the company has also signed an agreement with Trifecta Industries Inc, a leading player in the diamond industry, to commercialise the company's trace technology for diamonds. Under this agreement, Trifecta is going to invest US$500,000 in four tranches over a projected 10 month period to commercialise and scale SMX's patented technology for the diamond industry. The agreement signifies company's strategy in taking significant steps in commercialising its identification technology.
The company is working diligently to build strong relationships with leading companies globally and to expand its reach within the different sectors. The company also inked an agreement with The Perth Mint to commence full-scale development of bespoke mark and trace technology to be used exclusively by The Perth Mint, representing a significant achievement for the company as this was the first commercial agreement to be signed with a leading Australian company.
In the 2019 March quarter, the company signed an exclusive development and supply agreement with the medicinal cannabis distributor, CliniCann. Under this agreement, the company will be incorporating its revolutionary mark and trace technology into the primary and secondary packaging of all products manufactured by CliniCann's suppliers being distributed to all territories, excluding the USA.
During the March quarter, the company completed phase II testing of its seed integrity solution, with company's marking technology having no impact on the seeds' properties. It is expected that the phase III testing will begin in Q2 2019 and its completion will symbolise full commercialisation of SMX's agricultural offering. During the quarter, the company also completed electronics testing which successfully assessed SMX's ability to incorporate its mark and trace technology into existing manufacturing processes of large electronics manufacturers. This testing also demonstrates how easy it is to incorporate company's technology into the existing systems and processes of any manufacturer across all sectors.
The company is planning to secure additional collaboration agreements and proof of concept projects so that it could successfully deliver on business model and commercialise its disruptive technology with an edge over its peers for the competing technologies.
Advantages over Competing Technologies (Source: Company Report)
Recently, on 15th May 2019, the company held its Annual General Meeting, in which it passed six resolutions, which includes five ordinary and one special resolution. At the AGM, the shareholders gave their approval for an additional 10% Placement Capacity (Special resolution).
In the last three months, the share price of the company increased by 67.31%. SMX's stock last traded at $0.435, with a market capitalisation of circa $47.81 million as of 15th May 2019.
Previous articleA Lens Over Money3 Corporation's Business And Financial Performance For 1H FY19
Next articleWhat Investors Need To Know About Velocity Property Group
Data#3 Limited Riding High With Strong Rxpected FY19 Results
Three Australian IT Players – PPS, WSP And CL1
A Glance At Spectur Limited – An IT Player Revolutionising Security & Surveillance
Collaborate Corporation Rapidly Scaling in the Vehicle Subscription Market
Why is FZO zooming higher?
Recent Updates on Three IT Stocks: SRO, CV1, SMX
Silver To Outperform Gold Ahead?


text:
LDS Temple Dresses & Clothing in San Diego California
The San Diego California Temple is the 47th constructed and 45th operating temple of The Church of Jesus Christ of Latter-day Saints (LDS Church). Located near the La Jolla community of San Diego, it was built with two main spires, but unique to this temple are four smaller spires at the base of each main spire. The East spire is topped with the familiar Angel Moroni statue which adorns most LDS temples.
The San Diego Temple was announced on April 7, 1984, and dedicated on April 25, 1993 by Gordon B. Hinckley. The temple was built on a 7.2-acre (2.9 ha) plot, has 4 ordinance rooms and 8 sealing rooms, and has a total floor area of 72,000 square feet (6,700 m2).
Although there is no visitors' center, the church maintains the Mormon Battalion Historic Site in Old Town, San Diego.
7474 Charmant Dr
San Diego CA 92122-5000


text:
require 'sequel'

module Pupa
  class Processor
    class Connection
      # A proxy class to save plain old Ruby objects to PostgreSQL.
      class PostgreSQLAdapter
        include Pupa::Concerns::IndifferentAccess

        attr_reader :raw_connection

        # @param [String] database_url the database URL
        def initialize(database_url)
          @raw_connection = Sequel.connect(database_url)
        end

        # Finds a document matching the selection criteria.
        #
        # The selection criteria *must* set a `_type` key in order to determine
        # the collection to query.
        #
        # @param [Hash] selector the selection criteria
        # @return [Hash,nil] the matched document, or nil
        # @raises [Pupa::Errors::TooManyMatches] if multiple documents are found
        def find(selector)
          collection_name = collection_name_from_class_name(selector[:_type].camelize)
          if selector.except(:_type).empty?
            raise Errors::EmptySelectorError, "selector is empty during find in collection #{collection_name}"
          end
          collection = raw_connection[collection_name]
          query = collection.filter(symbolize_keys(selector))

          case query.count
          when 0
            nil
          when 1
            stringify_keys(query.first)
          else
            raise Errors::TooManyMatches, "selector matches multiple documents during find in collection #{collection_name}: #{JSON.dump(selector)}"
          end
        end

        # Inserts or replaces a document in PostgreSQL.
        #
        # @param [Object] object an object
        # @return [Array] whether the object was inserted and the object's database ID
        # @raises [Pupa::Errors::TooManyMatches] if multiple documents would be updated
        def save(object)
          fingerprint = symbolize_keys(object.fingerprint) # Sequel needs symbols
          selector = if fingerprint.key?(:$or) && fingerprint.size == 1
            Sequel.or(reject_subdocument_criteria(fingerprint[:$or]))
          else
            reject_subdocument_criteria(fingerprint)
          end

          collection_name = collection_name_from_class_name(object.class.to_s)
          if fingerprint.empty?
            raise Errors::EmptySelectorError, "selector is empty during save in collection #{collection_name} for #{object._id}"
          end
          collection = raw_connection[collection_name]
          query = collection.filter(selector)

          # Run query before callbacks to avoid e.g. timestamps in the selector.
          case query.count
          when 0
            object.run_callbacks(:save) do
              object.run_callbacks(:create) do
                collection.insert(object.to_h(persist: true))
                [true, object._id.to_s]
              end
            end
          when 1
            # Make the document available to the callbacks.
            # @see https://github.com/jpmckinney/pupa-ruby/issues/17
            object.document = stringify_keys(query.first)
            object.run_callbacks(:save) do
              query.update(object.to_h(persist: true).except(:_id))
              [false, object.document['_id'].to_s]
            end
          else
            raise Errors::TooManyMatches, "selector matches multiple documents during save in collection #{collection_name} for #{object._id}: #{JSON.dump(selector)}"
          end
        end

      private

        # Returns the name of the collection in which to save the object.
        #
        # @param [String] class_name the name of the object's class
        # @return [String] the name of the collection in which to save the object
        def collection_name_from_class_name(class_name)
          class_name.demodulize.underscore.pluralize.to_sym
        end

        def reject_subdocument_criteria(object)
          case object
          when Hash
            array = []
            object.each do |key,value|
              unless key.to_s['.'] # @todo Support MongoDB subdocument criteria.
                array += [key, reject_subdocument_criteria(value)]
              end
            end
            array
          when Array
            object.map do |value|
              reject_subdocument_criteria(value)
            end.reject(&:empty?)
          else
            object
          end
        end
      end
    end
  end
end


text:
Revenue & Tax
Data Bytes
Strong Economy Drives Robust Revenues, Though Benefits Not Felt By All
While the final state of New Hampshire's finances for FY 2016 will not be known for a few more months, the latest information on revenue collections provides an optimistic sign.
On July 5, the Department of Administrative Services released its last monthly Revenue Focus for the recently completed fiscal year, which ended June 30. After a solid FY 2015, collections grew by 5.7 percent in FY 2016 (excluding tax amnesty receipts). Unrestricted revenue for the General and Education Funds received during the entire fiscal year totaled $2.39 billion, which was nearly $100 million above what policymakers expected these two funds to collect. While the General and Education Funds have nearly 20 streams of revenue, combined business taxes did most of the heavy lifting, as collectively they received $75 million more than anticipated.
Yet, despite a much healthier and growing economy, the circumstances faced by some of our residents is not as favorable as one might expect. Below are some takeaways from the revenue results and recent economic data.
The General and Education Funds will likely experience a surplus in FY 2017.
According to the surplus statement for the General and Education Funds, budget writers planned for these two funds to receive approximately $2.32 billion in FY 2017. Given that revenues have been rising over the past few years in conjunction with the current stability in the New Hampshire economy, it is extremely likely that the state will receive at the very least the same amount it collected in FY 2016, $2.39 billion or close to $70 million above plan in FY 2017.
A second round of business tax rate reductions is virtually set in stone.
As part of a budget deal reached between Governor Hassan and state legislators last September, the statutory rates of the business profits tax and business enterprise tax were reduced from 8.5 percent to 8.2 percent and from 0.75 percent to 0.72 percent respectively. Also, under the law, if the General and Education Funds collect at least $4.64 billion over the FY 2016-2017 biennium, as reported in the state's audited comprehensive annual report, then the business profits tax rate will drop to 7.9 percent, while the business enterprise tax rate will be lowered to .675 percent. If this comes to fruition, the reduced rates will go into effect for tax year 2018.
As mentioned, revenue for the General and Education Funds totaled $2.39 billion in FY 2016. While this number is subject to minor revisions, it implies that these two funds only need to collect roughly $2.25 billion in FY 2017 to trigger an additional phase of rate reductions. For context, if this amount was collected, it would represent a nearly 6 percent reduction in collections from FY 2016. A measurable decline in collections is highly unlikely given the recent trend in revenues as well as the current condition of the New Hampshire economy. Consequently, outside of an enormous and unforeseen negative shock to the economy, further business tax cuts are a fait accompli.
From one angle, the New Hampshire economy is in great shape. Yet, at the same time there are some troubling symptoms.
A first pass at standard economic indicators suggests that the New Hampshire economy is faring quite well. The charts below illustrate this more fully. The first graph shows that there seems to have been an inflection point last summer for private employers, who are adding workers to their payrolls at a solid pace.
Second, Granite State employers, as a whole, have been paying out more to their employees in the form of wages. This sounds reasonable given that employers, outside of the public sector, have been adding more and more employees. However, one could argue that while the total is growing, each employed person might be receiving the same amount or even less. At first glance, that does not seem to be the case, as New Hampshire's average annual wage or annual wage per job has been steadily rising.
Third, while there is no New Hampshire measure of consumer confidence, households across the country in general feel much more confident about their financial situation and the economy than they did a few years ago. How households feel is important, because their psyche is often crucial to decisions they make to spend on consumer items or take another job. The combination of larger paychecks and more consumer confidence is manifesting itself in the Granite State, through higher revenue collections in the real estate transfer tax and the meals and rooms tax. Furthermore, according to the New Hampshire Automobile Dealers, automobile sales are their strongest in over a decade.
Yet, despite this evidence, there are other data points that appear at odds with this rosy picture. Whether you look at New Hampshire's poverty rate or the share of public school children eligible for free or reduced school lunches, the data clearly suggest that more households are struggling to provide the basics.
Additionally, median household income has not recovered from the damage done by the Great Recession. The graph below depicts median household income, both unadjusted (nominal dollars) and adjusted (real dollars) for the effects of inflation. In doing economic analysis, accounting for inflation is key because it helps determine if households are able to maintain their purchasing power or, put differently, buy the same basket of goods and services that they have been buying previously.
When accounting for inflation, the purchasing power of the bottom 50 percent of New Hampshire households has fallen. Now, it is unlikely that those households in the bottom 50 percent in 2007 are the exact same households in the bottom 50 percent today. It's plausible that younger households who started their careers in 2007 have gained work experience and seen some career progression. Nevertheless, it is troubling that collectively the bottom half of households cannot purchase as much as they could seven years ago.
Finally, there appears to be a contradiction in the data presented on the fortunes of the "typical" New Hampshire worker. On one hand, the data clearly shows that the average wage per job is growing steadily. However, on the other hand, the data shows that the median household has seen a decline in their income. What gives? Well, the disconnect stems from the fact that the average of anything assumes everyone gets an equal slice, which is often far from reality, and the average is prone to distortion by outliers or abnormal observations. For example, if we calculated the average of the following annual salaries…
$30,000, $35,000, and $50,000
…we would get $38,333, which does a decent job at reflecting what a "typical" person in this group earns. However, if you add someone who makes $1 million to this group, the average becomes $279,000, which represents none of these people very well. Why does this happen? Because by its very nature, the average can be heavily skewed, in this case by the fortunes of a very wealthy person. Consequently, the fact that the average pay per job in New Hampshire is steadily climbing says little about whether most people are experiencing more prosperity. On the other hand, the median is not subject to these distortions and can usually provide a better pulse on the fortunes of the middle class.
Connect With NHFPI
Subscribe to our e-newsletter for the latest updates
100 North Main Street | 4th Floor | Concord, NH 03301
603.856.8337 (phone) | 603.415.9543 (fax)
The New Hampshire Fiscal Policy Institute (NHFPI) is an independent nonprofit organization dedicated to exploring, developing, and promoting public policies that foster economic opportunity and prosperity for all New Hampshire residents, with an emphasis on low- and moderate-income families and individuals.
© New Hampshire Fiscal Policy Institute


Nature is made up of fractals. ORCHID FRACTAL is a new mixed media painting in an abstract fractal pattern with the beautiful colors of purple and turquoise found in orchids. I have studied fractals as part of my artistic journey whether it be in books or calendars. This painting is available at auction.


Queen Elizabeth I was the monarch when William Shakespeare was born and remained queen until her death in 1603. Elizabeth I had no consort. James I was her successor, and he remained on the throne when Shakespeare died in 1616.
James I married Anne of Denmark in 1589.
Shakespeare's early plays, those written in the 1590s, included both comedies and histories, the latter using the often tumultuous royal successions as inspiration. Shakespeare and his troupe were fairly successful and built their own theater, The Globe, in 1599.
James I was a supporter of the theater. Upon his coronation, the acting troupe changed its name to the King's Men. After 1600, Shakespeare's plays leaned toward tragedies, including Hamlet, King Lear and Macbeth.